1/* Copyright (C) 2003-2024 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
30static void
31wait_code (void)
32{
33 struct timespec ts = { .tv_sec = 0, .tv_nsec = 200000000 };
34 while (nanosleep (requested_time: &ts, remaining: &ts) < 0)
35 ;
36}
37
38
39#ifdef WAIT_IN_CHILD
40static pthread_barrier_t b;
41#endif
42
43static int
44thread_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 (s: 1000, ns: 0));
53 return pthread_clockjoin_np (th: thread, thread_return: retval, CLOCK_REALTIME, abstime: &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
64static void *
65tf1 (void *arg)
66{
67#ifdef WAIT_IN_CHILD
68 xpthread_barrier_wait (&b);
69
70 wait_code ();
71#endif
72
73 thread_join (thread: (pthread_t) arg, NULL);
74
75 exit (42);
76}
77
78
79static void *
80tf2 (void *arg)
81{
82#ifdef WAIT_IN_CHILD
83 xpthread_barrier_wait (&b);
84
85 wait_code ();
86#endif
87
88 thread_join (thread: (pthread_t) arg, NULL);
89
90 exit (43);
91}
92
93
94static int
95do_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 (thread: pthread_self (), NULL);
104 if (err == 0)
105 {
106 puts (s: "1st circular join succeeded");
107 return 1;
108 }
109 if (err != EDEADLK)
110 {
111 printf (format: "1st circular join %d, not EDEADLK\n", err);
112 return 1;
113 }
114
115 th = xpthread_create (NULL, thread_func: tf1, closure: (void *) pthread_self ());
116
117#ifndef WAIT_IN_CHILD
118 wait_code ();
119#endif
120
121 xpthread_cancel (thr: th);
122
123#ifdef WAIT_IN_CHILD
124 xpthread_barrier_wait (&b);
125#endif
126
127 void *r;
128 err = thread_join (thread: th, retval: &r);
129 if (err != 0)
130 {
131 printf (format: "cannot join 1st thread: %d\n", err);
132 return 1;
133 }
134 if (r != PTHREAD_CANCELED)
135 {
136 puts (s: "1st thread not canceled");
137 return 1;
138 }
139
140 err = thread_join (thread: pthread_self (), NULL);
141 if (err == 0)
142 {
143 puts (s: "2nd circular join succeeded");
144 return 1;
145 }
146 if (err != EDEADLK)
147 {
148 printf (format: "2nd circular join %d, not EDEADLK\n", err);
149 return 1;
150 }
151
152 th = xpthread_create (NULL, thread_func: tf2, closure: (void *) pthread_self ());
153
154#ifndef WAIT_IN_CHILD
155 wait_code ();
156#endif
157
158 xpthread_cancel (thr: th);
159
160#ifdef WAIT_IN_CHILD
161 xpthread_barrier_wait (&b);
162#endif
163
164 if (thread_join (thread: th, retval: &r) != 0)
165 {
166 puts (s: "cannot join 2nd thread");
167 return 1;
168 }
169 if (r != PTHREAD_CANCELED)
170 {
171 puts (s: "2nd thread not canceled");
172 return 1;
173 }
174
175 err = thread_join (thread: pthread_self (), NULL);
176 if (err == 0)
177 {
178 puts (s: "3rd circular join succeeded");
179 return 1;
180 }
181 if (err != EDEADLK)
182 {
183 printf (format: "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

source code of glibc/sysdeps/pthread/tst-join5.c