]>
Commit | Line | Data |
---|---|---|
c945a99f PA |
1 | /* This testcase is part of GDB, the GNU debugger. |
2 | ||
e2882c85 | 3 | Copyright 2014-2018 Free Software Foundation, Inc. |
c945a99f PA |
4 | |
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 3 of the License, or | |
8 | (at your option) any later version. | |
9 | ||
10 | This program 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 | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
17 | ||
18 | #define _GNU_SOURCE | |
19 | #include <assert.h> | |
20 | #include <pthread.h> | |
21 | #include <stdlib.h> | |
22 | #include <stdio.h> | |
23 | #include <unistd.h> | |
24 | #include <string.h> | |
25 | ||
26 | pthread_t main_thread; | |
27 | pthread_attr_t detached_attr; | |
28 | pthread_attr_t joinable_attr; | |
29 | ||
30 | /* Number of threads we'll create of each variant | |
31 | (joinable/detached). */ | |
32 | int n_threads = 50; | |
33 | ||
34 | /* Mutex used to hold creating detached threads. */ | |
35 | pthread_mutex_t dthrds_create_mutex; | |
36 | ||
37 | /* Wrapper for pthread_create. */ | |
38 | ||
39 | void | |
40 | create_thread (pthread_attr_t *attr, | |
41 | void *(*start_routine) (void *), void *arg) | |
42 | { | |
43 | pthread_t child; | |
44 | int rc; | |
45 | ||
46 | while ((rc = pthread_create (&child, attr, start_routine, arg)) != 0) | |
47 | { | |
48 | fprintf (stderr, "unexpected error from pthread_create: %s (%d)\n", | |
49 | strerror (rc), rc); | |
50 | sleep (1); | |
51 | } | |
52 | } | |
53 | ||
54 | void | |
55 | break_fn (void) | |
56 | { | |
57 | } | |
58 | ||
59 | /* Data passed to joinable threads on creation. This is allocated on | |
60 | the heap and ownership transferred from parent to child. (We do | |
61 | this because it's not portable to cast pthread_t to pointer.) */ | |
62 | ||
63 | struct thread_arg | |
64 | { | |
65 | pthread_t parent; | |
66 | }; | |
67 | ||
68 | /* Entry point for joinable threads. These threads first join their | |
69 | parent before spawning a new child (and exiting). The parent's tid | |
70 | is passed as pthread_create argument, encapsulated in a struct | |
71 | thread_arg object. */ | |
72 | ||
73 | void * | |
74 | joinable_fn (void *arg) | |
75 | { | |
76 | struct thread_arg *p = arg; | |
77 | ||
78 | pthread_setname_np (pthread_self (), "joinable"); | |
79 | ||
80 | if (p->parent != main_thread) | |
81 | assert (pthread_join (p->parent, NULL) == 0); | |
82 | ||
83 | p->parent = pthread_self (); | |
84 | ||
85 | create_thread (&joinable_attr, joinable_fn, p); | |
86 | ||
87 | break_fn (); | |
88 | ||
89 | return NULL; | |
90 | } | |
91 | ||
92 | /* Entry point for detached threads. */ | |
93 | ||
94 | void * | |
95 | detached_fn (void *arg) | |
96 | { | |
97 | pthread_setname_np (pthread_self (), "detached"); | |
98 | ||
99 | /* This should throttle threads a bit in case we manage to spawn | |
100 | threads faster than they exit. */ | |
101 | pthread_mutex_lock (&dthrds_create_mutex); | |
102 | ||
103 | create_thread (&detached_attr, detached_fn, NULL); | |
104 | ||
105 | /* Note this is called before the mutex is unlocked otherwise in | |
106 | non-stop mode, when the breakpoint is hit we'd keep spawning more | |
107 | threads forever while the old threads stay alive (stopped in the | |
108 | breakpoint). */ | |
109 | break_fn (); | |
110 | ||
111 | pthread_mutex_unlock (&dthrds_create_mutex); | |
112 | ||
113 | return NULL; | |
114 | } | |
115 | ||
e584fdbc PA |
116 | /* Allow for as much timeout as DejaGnu wants, plus a bit of |
117 | slack. */ | |
118 | #define SECONDS (TIMEOUT + 20) | |
119 | ||
120 | /* We'll exit after this many seconds. */ | |
121 | unsigned int seconds_left = SECONDS; | |
122 | ||
123 | /* GDB sets this whenever it's about to start a new detach/attach | |
124 | sequence. We react by resetting the seconds left counter. */ | |
125 | volatile int again = 0; | |
126 | ||
c945a99f PA |
127 | int |
128 | main (int argc, char *argv[]) | |
129 | { | |
130 | int i; | |
131 | ||
132 | if (argc > 1) | |
133 | n_threads = atoi (argv[1]); | |
134 | ||
135 | pthread_mutex_init (&dthrds_create_mutex, NULL); | |
136 | ||
137 | pthread_attr_init (&detached_attr); | |
138 | pthread_attr_setdetachstate (&detached_attr, PTHREAD_CREATE_DETACHED); | |
139 | pthread_attr_init (&joinable_attr); | |
140 | pthread_attr_setdetachstate (&joinable_attr, PTHREAD_CREATE_JOINABLE); | |
141 | ||
142 | main_thread = pthread_self (); | |
143 | ||
144 | /* Spawn the initial set of test threads. Some threads are | |
145 | joinable, others are detached. This exercises different code | |
146 | paths in the runtime. */ | |
147 | for (i = 0; i < n_threads; ++i) | |
148 | { | |
149 | struct thread_arg *p; | |
150 | ||
151 | p = malloc (sizeof *p); | |
152 | p->parent = main_thread; | |
153 | create_thread (&joinable_attr, joinable_fn, p); | |
154 | ||
155 | create_thread (&detached_attr, detached_fn, NULL); | |
156 | } | |
157 | ||
e584fdbc PA |
158 | /* Exit after a while if GDB is gone/crashes. But wait long enough |
159 | for one attach/detach sequence done by the .exp file. */ | |
160 | while (--seconds_left > 0) | |
161 | { | |
162 | sleep (1); | |
163 | ||
164 | if (again) | |
165 | { | |
166 | /* GDB should be reattaching soon. Restart the timer. */ | |
167 | again = 0; | |
168 | seconds_left = SECONDS; | |
169 | } | |
170 | } | |
171 | ||
172 | printf ("timeout, exiting\n"); | |
c945a99f PA |
173 | return 0; |
174 | } |