1 /* Copyright (C) 2003-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 <stdio.h>
21 #include <stdlib.h>
22 #include <time.h>
23 #include <unistd.h>
24
25 #include <support/check.h>
26 #include <support/timespec.h>
27 #include <support/xthread.h>
28 #include <support/xtime.h>
29
30 static void
wait_code(void)31 wait_code (void)
32 {
33 struct timespec ts = { .tv_sec = 0, .tv_nsec = 200000000 };
34 while (nanosleep (&ts, &ts) < 0)
35 ;
36 }
37
38
39 #ifdef WAIT_IN_CHILD
40 static pthread_barrier_t b;
41 #endif
42
43 static int
thread_join(pthread_t thread,void ** retval)44 thread_join (pthread_t thread, void **retval)
45 {
46 #if defined USE_PTHREAD_TIMEDJOIN_NP
47 const struct timespec ts = timespec_add (xclock_now (CLOCK_REALTIME),
48 make_timespec (1000, 0));
49 return pthread_timedjoin_np (thread, retval, &ts);
50 #elif defined USE_PTHREAD_CLOCKJOIN_NP_REALTIME
51 const struct timespec ts = timespec_add (xclock_now (CLOCK_REALTIME),
52 make_timespec (1000, 0));
53 return pthread_clockjoin_np (thread, retval, CLOCK_REALTIME, &ts);
54 #elif defined USE_PTHREAD_CLOCKJOIN_NP_MONOTONIC
55 const struct timespec ts = timespec_add (xclock_now (CLOCK_MONOTONIC),
56 make_timespec (1000, 0));
57 return pthread_clockjoin_np (thread, retval, CLOCK_MONOTONIC, &ts);
58 #else
59 return pthread_join (thread, retval);
60 #endif
61 }
62
63
64 static void *
tf1(void * arg)65 tf1 (void *arg)
66 {
67 #ifdef WAIT_IN_CHILD
68 xpthread_barrier_wait (&b);
69
70 wait_code ();
71 #endif
72
73 thread_join ((pthread_t) arg, NULL);
74
75 exit (42);
76 }
77
78
79 static void *
tf2(void * arg)80 tf2 (void *arg)
81 {
82 #ifdef WAIT_IN_CHILD
83 xpthread_barrier_wait (&b);
84
85 wait_code ();
86 #endif
87
88 thread_join ((pthread_t) arg, NULL);
89
90 exit (43);
91 }
92
93
94 static int
do_test(void)95 do_test (void)
96 {
97 #ifdef WAIT_IN_CHILD
98 xpthread_barrier_init (&b, NULL, 2);
99 #endif
100
101 pthread_t th;
102
103 int err = thread_join (pthread_self (), NULL);
104 if (err == 0)
105 {
106 puts ("1st circular join succeeded");
107 return 1;
108 }
109 if (err != EDEADLK)
110 {
111 printf ("1st circular join %d, not EDEADLK\n", err);
112 return 1;
113 }
114
115 th = xpthread_create (NULL, tf1, (void *) pthread_self ());
116
117 #ifndef WAIT_IN_CHILD
118 wait_code ();
119 #endif
120
121 xpthread_cancel (th);
122
123 #ifdef WAIT_IN_CHILD
124 xpthread_barrier_wait (&b);
125 #endif
126
127 void *r;
128 err = thread_join (th, &r);
129 if (err != 0)
130 {
131 printf ("cannot join 1st thread: %d\n", err);
132 return 1;
133 }
134 if (r != PTHREAD_CANCELED)
135 {
136 puts ("1st thread not canceled");
137 return 1;
138 }
139
140 err = thread_join (pthread_self (), NULL);
141 if (err == 0)
142 {
143 puts ("2nd circular join succeeded");
144 return 1;
145 }
146 if (err != EDEADLK)
147 {
148 printf ("2nd circular join %d, not EDEADLK\n", err);
149 return 1;
150 }
151
152 th = xpthread_create (NULL, tf2, (void *) pthread_self ());
153
154 #ifndef WAIT_IN_CHILD
155 wait_code ();
156 #endif
157
158 xpthread_cancel (th);
159
160 #ifdef WAIT_IN_CHILD
161 xpthread_barrier_wait (&b);
162 #endif
163
164 if (thread_join (th, &r) != 0)
165 {
166 puts ("cannot join 2nd thread");
167 return 1;
168 }
169 if (r != PTHREAD_CANCELED)
170 {
171 puts ("2nd thread not canceled");
172 return 1;
173 }
174
175 err = thread_join (pthread_self (), NULL);
176 if (err == 0)
177 {
178 puts ("3rd circular join succeeded");
179 return 1;
180 }
181 if (err != EDEADLK)
182 {
183 printf ("3rd circular join %d, not EDEADLK\n", err);
184 return 1;
185 }
186
187 return 0;
188 }
189
190 #include <support/test-driver.c>
191