]>
Commit | Line | Data |
---|---|---|
b126ec4b MK |
1 | .\" Copyright (c) 2008 Linux Foundation, written by Michael Kerrisk |
2 | .\" <mtk.manpages@gmail.com> | |
3 | .\" | |
5fbde956 | 4 | .\" SPDX-License-Identifier: Linux-man-pages-copyleft |
b126ec4b | 5 | .\" |
4c1c5274 | 6 | .TH pthread_cleanup_push 3 (date) "Linux man-pages (unreleased)" |
b126ec4b MK |
7 | .SH NAME |
8 | pthread_cleanup_push, pthread_cleanup_pop \- push and pop | |
1f08fc80 | 9 | thread cancelation clean-up handlers |
caba145c AC |
10 | .SH LIBRARY |
11 | POSIX threads library | |
8fc3b2cf | 12 | .RI ( libpthread ", " \-lpthread ) |
b126ec4b MK |
13 | .SH SYNOPSIS |
14 | .nf | |
15 | .B #include <pthread.h> | |
f90f031e | 16 | .PP |
15d65653 | 17 | .BI "void pthread_cleanup_push(void (*" routine ")(void *), void *" arg ); |
b126ec4b | 18 | .BI "void pthread_cleanup_pop(int " execute ); |
6030f2d8 | 19 | .fi |
b126ec4b MK |
20 | .SH DESCRIPTION |
21 | These functions manipulate the calling thread's stack of | |
1f08fc80 | 22 | thread-cancelation clean-up handlers. |
b126ec4b MK |
23 | A clean-up handler is a function that is automatically executed |
24 | when a thread is canceled (or in various other circumstances | |
25 | described below); | |
26 | it might, for example, unlock a mutex so that | |
27 | it becomes available to other threads in the process. | |
847e0d88 | 28 | .PP |
b126ec4b MK |
29 | The |
30 | .BR pthread_cleanup_push () | |
31 | function pushes | |
32 | .I routine | |
33 | onto the top of the stack of clean-up handlers. | |
34 | When | |
35 | .I routine | |
36 | is later invoked, it will be given | |
37 | .I arg | |
38 | as its argument. | |
847e0d88 | 39 | .PP |
b126ec4b MK |
40 | The |
41 | .BR pthread_cleanup_pop () | |
42 | function removes the routine at the top of the stack of clean-up handlers, | |
43 | and optionally executes it if | |
44 | .I execute | |
c7094399 | 45 | is nonzero. |
847e0d88 | 46 | .PP |
1f08fc80 | 47 | A cancelation clean-up handler is popped from the stack |
b126ec4b | 48 | and executed in the following circumstances: |
22356d97 | 49 | .IP \(bu 3 |
b126ec4b MK |
50 | When a thread is canceled, |
51 | all of the stacked clean-up handlers are popped and executed in | |
52 | the reverse of the order in which they were pushed onto the stack. | |
22356d97 | 53 | .IP \(bu |
b126ec4b MK |
54 | When a thread terminates by calling |
55 | .BR pthread_exit (3), | |
56 | all clean-up handlers are executed as described in the preceding point. | |
c6fa0841 MK |
57 | (Clean-up handlers are |
58 | .I not | |
59 | called if the thread terminates by | |
b126ec4b MK |
60 | performing a |
61 | .I return | |
62 | from the thread start function.) | |
22356d97 | 63 | .IP \(bu |
b126ec4b MK |
64 | When a thread calls |
65 | .BR pthread_cleanup_pop () | |
c7094399 | 66 | with a nonzero |
b126ec4b MK |
67 | .I execute |
68 | argument, the top-most clean-up handler is popped and executed. | |
69 | .PP | |
70 | POSIX.1 permits | |
71 | .BR pthread_cleanup_push () | |
72 | and | |
73 | .BR pthread_cleanup_pop () | |
74 | to be implemented as macros that expand to text | |
75 | containing \(aq\fB{\fP\(aq and \(aq\fB}\fP\(aq, respectively. | |
76 | For this reason, the caller must ensure that calls to these | |
77 | functions are paired within the same function, | |
78 | and at the same lexical nesting level. | |
33a0ccb2 | 79 | (In other words, a clean-up handler is established only |
b126ec4b | 80 | during the execution of a specified section of code.) |
847e0d88 | 81 | .PP |
b126ec4b | 82 | Calling |
a113945f | 83 | .BR longjmp (3) |
b126ec4b MK |
84 | .RB ( siglongjmp (3)) |
85 | produces undefined results if any call has been made to | |
86 | .BR pthread_cleanup_push () | |
87 | or | |
88 | .BR pthread_cleanup_pop () | |
89 | without the matching call of the pair since the jump buffer | |
90 | was filled by | |
91 | .BR setjmp (3) | |
92 | .RB ( sigsetjmp (3)). | |
93 | Likewise, calling | |
a113945f | 94 | .BR longjmp (3) |
b126ec4b MK |
95 | .RB ( siglongjmp (3)) |
96 | from inside a clean-up handler produces undefined results | |
97 | unless the jump buffer was also filled by | |
98 | .BR setjmp (3) | |
99 | .RB ( sigsetjmp (3)) | |
100 | inside the handler. | |
101 | .SH RETURN VALUE | |
102 | These functions do not return a value. | |
103 | .SH ERRORS | |
104 | There are no errors. | |
105 | .\" SH VERSIONS | |
106 | .\" Available since glibc 2.0 | |
598445e0 ZL |
107 | .SH ATTRIBUTES |
108 | For an explanation of the terms used in this section, see | |
109 | .BR attributes (7). | |
c466875e MK |
110 | .ad l |
111 | .nh | |
598445e0 ZL |
112 | .TS |
113 | allbox; | |
c466875e | 114 | lbx lb lb |
598445e0 ZL |
115 | l l l. |
116 | Interface Attribute Value | |
117 | T{ | |
118 | .BR pthread_cleanup_push (), | |
119 | .BR pthread_cleanup_pop () | |
120 | T} Thread safety MT-Safe | |
121 | .TE | |
c466875e MK |
122 | .hy |
123 | .ad | |
847e0d88 | 124 | .sp 1 |
3113c7f3 | 125 | .SH STANDARDS |
6cd59aeb | 126 | POSIX.1-2001, POSIX.1-2008. |
b126ec4b | 127 | .SH NOTES |
a113945f | 128 | On Linux, the |
b126ec4b MK |
129 | .BR pthread_cleanup_push () |
130 | and | |
131 | .BR pthread_cleanup_pop () | |
c6fa0841 MK |
132 | functions |
133 | .I are | |
134 | implemented as macros that expand to text | |
b126ec4b MK |
135 | containing \(aq\fB{\fP\(aq and \(aq\fB}\fP\(aq, respectively. |
136 | This means that variables declared within the scope of | |
33a0ccb2 | 137 | paired calls to these functions will be visible within only that scope. |
847e0d88 | 138 | .PP |
28e00ccf MK |
139 | POSIX.1 |
140 | .\" The text was actually added in the 2004 TC2 | |
141 | says that the effect of using | |
142 | .IR return , | |
143 | .IR break , | |
144 | .IR continue , | |
145 | or | |
1ae6b2c7 | 146 | .I goto |
a113945f | 147 | to prematurely leave a block bracketed |
28e00ccf MK |
148 | .BR pthread_cleanup_push () |
149 | and | |
150 | .BR pthread_cleanup_pop () | |
151 | is undefined. | |
152 | Portable applications should avoid doing this. | |
a14af333 | 153 | .SH EXAMPLES |
b126ec4b MK |
154 | The program below provides a simple example of the use of the functions |
155 | described in this page. | |
156 | The program creates a thread that executes a loop bracketed by | |
157 | .BR pthread_cleanup_push () | |
158 | and | |
159 | .BR pthread_cleanup_pop (). | |
f90fec66 | 160 | This loop increments a global variable, |
b126ec4b MK |
161 | .IR cnt , |
162 | once each second. | |
163 | Depending on what command-line arguments are supplied, | |
1f08fc80 | 164 | the main thread sends the other thread a cancelation request, |
b126ec4b MK |
165 | or sets a global variable that causes the other thread |
166 | to exit its loop and terminate normally (by doing a | |
167 | .IR return ). | |
847e0d88 | 168 | .PP |
b126ec4b | 169 | In the following shell session, |
1f08fc80 | 170 | the main thread sends a cancelation request to the other thread: |
847e0d88 | 171 | .PP |
b126ec4b | 172 | .in +4n |
b8302363 | 173 | .EX |
b126ec4b MK |
174 | $ \fB./a.out\fP |
175 | New thread started | |
176 | cnt = 0 | |
177 | cnt = 1 | |
178 | Canceling thread | |
d064d41a | 179 | Called clean\-up handler |
b126ec4b | 180 | Thread was canceled; cnt = 0 |
b8302363 | 181 | .EE |
b126ec4b | 182 | .in |
847e0d88 | 183 | .PP |
b126ec4b | 184 | From the above, we see that the thread was canceled, |
1f08fc80 | 185 | and that the cancelation clean-up handler was called |
b126ec4b MK |
186 | and it reset the value of the global variable |
187 | .I cnt | |
188 | to 0. | |
847e0d88 | 189 | .PP |
b126ec4b MK |
190 | In the next run, the main program sets a |
191 | global variable that causes other thread to terminate normally: | |
847e0d88 | 192 | .PP |
b126ec4b | 193 | .in +4n |
b8302363 | 194 | .EX |
b126ec4b MK |
195 | $ \fB./a.out x\fP |
196 | New thread started | |
197 | cnt = 0 | |
198 | cnt = 1 | |
199 | Thread terminated normally; cnt = 2 | |
b8302363 | 200 | .EE |
b126ec4b | 201 | .in |
847e0d88 | 202 | .PP |
b126ec4b MK |
203 | From the above, we see that the clean-up handler was not executed (because |
204 | .I cleanup_pop_arg | |
205 | was 0), and therefore the value of | |
206 | .I cnt | |
207 | was not reset. | |
847e0d88 | 208 | .PP |
b126ec4b MK |
209 | In the next run, the main program sets a global variable that |
210 | causes the other thread to terminate normally, | |
c7094399 | 211 | and supplies a nonzero value for |
b126ec4b | 212 | .IR cleanup_pop_arg : |
847e0d88 | 213 | .PP |
b126ec4b | 214 | .in +4n |
b8302363 | 215 | .EX |
b126ec4b MK |
216 | $ \fB./a.out x 1\fP |
217 | New thread started | |
218 | cnt = 0 | |
219 | cnt = 1 | |
d064d41a | 220 | Called clean\-up handler |
b126ec4b | 221 | Thread terminated normally; cnt = 0 |
b8302363 | 222 | .EE |
b126ec4b | 223 | .in |
847e0d88 | 224 | .PP |
b126ec4b MK |
225 | In the above, we see that although the thread was not canceled, |
226 | the clean-up handler was executed, because the argument given to | |
227 | .BR pthread_cleanup_pop () | |
c7094399 | 228 | was nonzero. |
b126ec4b MK |
229 | .SS Program source |
230 | \& | |
b0b6ab4e | 231 | .\" SRC BEGIN (pthread_cleanup_push.c) |
e7d0bb47 | 232 | .EX |
ad3868f0 | 233 | #include <errno.h> |
b126ec4b | 234 | #include <pthread.h> |
b126ec4b MK |
235 | #include <stdio.h> |
236 | #include <stdlib.h> | |
ad3868f0 | 237 | #include <sys/types.h> |
b126ec4b | 238 | #include <unistd.h> |
b126ec4b | 239 | |
d1a71985 | 240 | #define handle_error_en(en, msg) \e |
b126ec4b MK |
241 | do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0) |
242 | ||
243 | static int done = 0; | |
244 | static int cleanup_pop_arg = 0; | |
245 | static int cnt = 0; | |
246 | ||
247 | static void | |
248 | cleanup_handler(void *arg) | |
249 | { | |
d1a71985 | 250 | printf("Called clean\-up handler\en"); |
b126ec4b MK |
251 | cnt = 0; |
252 | } | |
253 | ||
254 | static void * | |
255 | thread_start(void *arg) | |
256 | { | |
f1e39c1e | 257 | time_t curr; |
b126ec4b | 258 | |
d1a71985 | 259 | printf("New thread started\en"); |
b126ec4b MK |
260 | |
261 | pthread_cleanup_push(cleanup_handler, NULL); | |
262 | ||
f1e39c1e | 263 | curr = time(NULL); |
b126ec4b MK |
264 | |
265 | while (!done) { | |
1f08fc80 | 266 | pthread_testcancel(); /* A cancelation point */ |
b126ec4b MK |
267 | if (curr < time(NULL)) { |
268 | curr = time(NULL); | |
1f08fc80 | 269 | printf("cnt = %d\en", cnt); /* A cancelation point */ |
b126ec4b MK |
270 | cnt++; |
271 | } | |
272 | } | |
273 | ||
274 | pthread_cleanup_pop(cleanup_pop_arg); | |
275 | return NULL; | |
276 | } | |
277 | ||
278 | int | |
279 | main(int argc, char *argv[]) | |
280 | { | |
281 | pthread_t thr; | |
282 | int s; | |
283 | void *res; | |
284 | ||
0ac743c5 | 285 | s = pthread_create(&thr, NULL, thread_start, NULL); |
b126ec4b MK |
286 | if (s != 0) |
287 | handle_error_en(s, "pthread_create"); | |
288 | ||
289 | sleep(2); /* Allow new thread to run a while */ | |
290 | ||
291 | if (argc > 1) { | |
292 | if (argc > 2) | |
293 | cleanup_pop_arg = atoi(argv[2]); | |
294 | done = 1; | |
295 | ||
296 | } else { | |
d1a71985 | 297 | printf("Canceling thread\en"); |
b126ec4b MK |
298 | s = pthread_cancel(thr); |
299 | if (s != 0) | |
300 | handle_error_en(s, "pthread_cancel"); | |
301 | } | |
302 | ||
303 | s = pthread_join(thr, &res); | |
304 | if (s != 0) | |
305 | handle_error_en(s, "pthread_join"); | |
306 | ||
307 | if (res == PTHREAD_CANCELED) | |
d1a71985 | 308 | printf("Thread was canceled; cnt = %d\en", cnt); |
b126ec4b | 309 | else |
d1a71985 | 310 | printf("Thread terminated normally; cnt = %d\en", cnt); |
b126ec4b MK |
311 | exit(EXIT_SUCCESS); |
312 | } | |
e7d0bb47 | 313 | .EE |
b0b6ab4e | 314 | .\" SRC END |
b126ec4b MK |
315 | .SH SEE ALSO |
316 | .BR pthread_cancel (3), | |
317 | .BR pthread_cleanup_push_defer_np (3), | |
318 | .BR pthread_setcancelstate (3), | |
319 | .BR pthread_testcancel (3), | |
320 | .BR pthreads (7) |