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 <stdbool.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <time.h>
25 #include <sys/time.h>
26 
27 
28 typedef struct
29   {
30     pthread_cond_t cond;
31     pthread_mutex_t lock;
32     pthread_t h;
33   } T;
34 
35 
36 static volatile bool done;
37 
38 
39 static void *
tf(void * arg)40 tf (void *arg)
41 {
42   puts ("child created");
43 
44   if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0
45       || pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL) != 0)
46     {
47       puts ("cannot set cancellation options");
48       exit (1);
49     }
50 
51   T *t = (T *) arg;
52 
53   if (pthread_mutex_lock (&t->lock) != 0)
54     {
55       puts ("child: lock failed");
56       exit (1);
57     }
58 
59   done = true;
60 
61   if (pthread_cond_signal (&t->cond) != 0)
62     {
63       puts ("child: cond_signal failed");
64       exit (1);
65     }
66 
67   if (pthread_cond_wait (&t->cond, &t->lock) != 0)
68     {
69       puts ("child: cond_wait failed");
70       exit (1);
71     }
72 
73   if (pthread_mutex_unlock (&t->lock) != 0)
74     {
75       puts ("child: unlock failed");
76       exit (1);
77     }
78 
79   return NULL;
80 }
81 
82 
83 static int
do_test(void)84 do_test (void)
85 {
86   int i;
87 #define N 100
88   T *t[N];
89   for (i = 0; i < N; ++i)
90     {
91       printf ("round %d\n", i);
92 
93       t[i] = (T *) malloc (sizeof (T));
94       if (t[i] == NULL)
95 	{
96 	  puts ("out of memory");
97 	  exit (1);
98 	}
99 
100       if (pthread_mutex_init (&t[i]->lock, NULL) != 0
101 	  || pthread_cond_init (&t[i]->cond, NULL) != 0)
102 	{
103 	  puts ("an _init function failed");
104 	  exit (1);
105 	}
106 
107       if (pthread_mutex_lock (&t[i]->lock) != 0)
108 	{
109 	  puts ("initial mutex_lock failed");
110 	  exit (1);
111 	}
112 
113       done = false;
114 
115       if (pthread_create (&t[i]->h, NULL, tf, t[i]) != 0)
116 	{
117 	  puts ("pthread_create failed");
118 	  exit (1);
119 	}
120 
121       do
122 	if (pthread_cond_wait (&t[i]->cond, &t[i]->lock) != 0)
123 	  {
124 	    puts ("cond_wait failed");
125 	    exit (1);
126 	  }
127       while (! done);
128 
129       /* Release the lock since the cancel handler will get it.  */
130       if (pthread_mutex_unlock (&t[i]->lock) != 0)
131 	{
132 	  puts ("mutex_unlock failed");
133 	  exit (1);
134 	}
135 
136       if (pthread_cancel (t[i]->h) != 0)
137 	{
138 	  puts ("cancel failed");
139 	  exit (1);
140 	}
141 
142       puts ("parent: joining now");
143 
144       void *result;
145       if (pthread_join (t[i]->h, &result) != 0)
146 	{
147 	  puts ("join failed");
148 	  exit (1);
149 	}
150 
151       if (result != PTHREAD_CANCELED)
152 	{
153 	  puts ("result != PTHREAD_CANCELED");
154 	  exit (1);
155 	}
156     }
157 
158   for (i = 0; i < N; ++i)
159     free (t[i]);
160 
161   return 0;
162 }
163 
164 
165 #define TEST_FUNCTION do_test ()
166 #include "../test-skeleton.c"
167