1 /* Copyright (C) 2003 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library 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 GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
18 
19 #include <pthread.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 
24 
25 static pthread_barrier_t bar;
26 
27 static int global;
28 
29 
30 static void
cleanup(void * arg)31 cleanup (void *arg)
32 {
33   global = 1;
34 }
35 
36 
37 static void *
tf(void * arg)38 tf (void *arg)
39 {
40   /* Enable cancellation, but defer it.  */
41   if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0)
42     {
43       puts ("setcancelstate failed");
44       exit (1);
45     }
46   if (pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL) != 0)
47     {
48       puts ("setcanceltype failed");
49       exit (1);
50     }
51 
52   /* Add cleanup handler.  */
53   pthread_cleanup_push (cleanup, NULL);
54 
55   /* Synchronize with the main thread.  */
56   int r = pthread_barrier_wait (&bar);
57   if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
58     {
59       puts ("tf: first barrier_wait failed");
60       exit (1);
61     }
62 
63   /* And again.  Once this is done the main thread should have canceled
64      this thread.  */
65   r = pthread_barrier_wait (&bar);
66   if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
67     {
68       puts ("tf: second barrier_wait failed");
69       exit (1);
70     }
71 
72   /* Remove the cleanup handler without executing it.  */
73   pthread_cleanup_pop (0);
74 
75   /* Now react on the cancellation.  */
76   pthread_testcancel ();
77 
78   /* This call should never return.  */
79   return NULL;
80 }
81 
82 
83 static int
do_test(void)84 do_test (void)
85 {
86   if (pthread_barrier_init (&bar, NULL, 2) != 0)
87     {
88       puts ("barrier_init failed");
89       exit (1);
90     }
91 
92   pthread_t th;
93   if (pthread_create (&th, NULL, tf, NULL) != 0)
94     {
95       puts ("pthread_create failed");
96       return 1;
97     }
98 
99   int r = pthread_barrier_wait (&bar);
100   if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
101     {
102       puts ("first barrier_wait failed");
103       exit (1);
104     }
105 
106   if (pthread_cancel (th) != 0)
107     {
108       puts ("pthread_cancel failed");
109       return 1;
110     }
111 
112   r = pthread_barrier_wait (&bar);
113   if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
114     {
115       puts ("second barrier_wait failed");
116       exit (1);
117     }
118 
119   void *result;
120   if (pthread_join (th, &result) != 0)
121     {
122       puts ("pthread_join failed");
123       return 1;
124     }
125 
126   if (result != PTHREAD_CANCELED)
127     {
128       puts ("thread was not canceled");
129       exit (1);
130     }
131 
132   if (global != 0)
133     {
134       puts ("cancellation handler has been called");
135       exit (1);
136     }
137 
138   return 0;
139 }
140 
141 #define TEST_FUNCTION do_test ()
142 #include "../test-skeleton.c"
143