1PTHREAD_CLEANUP_POP(3P) POSIX Programmer's Manual PTHREAD_CLEANUP_POP(3P)
2
3
4
6 This manual page is part of the POSIX Programmer's Manual. The Linux
7 implementation of this interface may differ (consult the corresponding
8 Linux manual page for details of Linux behavior), or the interface may
9 not be implemented on Linux.
10
11
13 pthread_cleanup_pop, pthread_cleanup_push — establish cancellation han‐
14 dlers
15
17 #include <pthread.h>
18
19 void pthread_cleanup_pop(int execute);
20 void pthread_cleanup_push(void (*routine)(void*), void *arg);
21
23 The pthread_cleanup_pop() function shall remove the routine at the top
24 of the calling thread's cancellation cleanup stack and optionally
25 invoke it (if execute is non-zero).
26
27 The pthread_cleanup_push() function shall push the specified cancella‐
28 tion cleanup handler routine onto the calling thread's cancellation
29 cleanup stack. The cancellation cleanup handler shall be popped from
30 the cancellation cleanup stack and invoked with the argument arg when:
31
32 * The thread exits (that is, calls pthread_exit()).
33
34 * The thread acts upon a cancellation request.
35
36 * The thread calls pthread_cleanup_pop() with a non-zero execute
37 argument.
38
39 These functions may be implemented as macros. The application shall
40 ensure that they appear as statements, and in pairs within the same
41 lexical scope (that is, the pthread_cleanup_push() macro may be thought
42 to expand to a token list whose first token is '{' with
43 pthread_cleanup_pop() expanding to a token list whose last token is the
44 corresponding '}').
45
46 The effect of calling longjmp() or siglongjmp() is undefined if there
47 have been any calls to pthread_cleanup_push() or pthread_cleanup_pop()
48 made without the matching call since the jump buffer was filled. The
49 effect of calling longjmp() or siglongjmp() from inside a cancellation
50 cleanup handler is also undefined unless the jump buffer was also
51 filled in the cancellation cleanup handler.
52
53 The effect of the use of return, break, continue, and goto to prema‐
54 turely leave a code block described by a pair of pthread_cleanup_push()
55 and pthread_cleanup_pop() functions calls is undefined.
56
58 The pthread_cleanup_push() and pthread_cleanup_pop() functions shall
59 not return a value.
60
62 No errors are defined.
63
64 These functions shall not return an error code of [EINTR].
65
66 The following sections are informative.
67
69 The following is an example using thread primitives to implement a can‐
70 celable, writers-priority read-write lock:
71
72 typedef struct {
73 pthread_mutex_t lock;
74 pthread_cond_t rcond,
75 wcond;
76 int lock_count; /* < 0 .. Held by writer. */
77 /* > 0 .. Held by lock_count readers. */
78 /* = 0 .. Held by nobody. */
79 int waiting_writers; /* Count of waiting writers. */
80 } rwlock;
81
82 void
83 waiting_reader_cleanup(void *arg)
84 {
85 rwlock *l;
86
87 l = (rwlock *) arg;
88 pthread_mutex_unlock(&l->lock);
89 }
90
91 void
92 lock_for_read(rwlock *l)
93 {
94 pthread_mutex_lock(&l->lock);
95 pthread_cleanup_push(waiting_reader_cleanup, l);
96 while ((l->lock_count < 0) || (l->waiting_writers != 0))
97 pthread_cond_wait(&l->rcond, &l->lock);
98 l->lock_count++;
99 /*
100 * Note the pthread_cleanup_pop executes
101 * waiting_reader_cleanup.
102 */
103 pthread_cleanup_pop(1);
104 }
105
106 void
107 release_read_lock(rwlock *l)
108 {
109 pthread_mutex_lock(&l->lock);
110 if (--l->lock_count == 0)
111 pthread_cond_signal(&l->wcond);
112 pthread_mutex_unlock(&l->lock);
113 }
114
115 void
116 waiting_writer_cleanup(void *arg)
117 {
118 rwlock *l;
119
120 l = (rwlock *) arg;
121 if ((--l->waiting_writers == 0) && (l->lock_count >= 0)) {
122 /*
123 * This only happens if we have been canceled. If the
124 * lock is not held by a writer, there may be readers who
125 * were blocked because waiting_writers was positive; they
126 * can now be unblocked.
127 */
128 pthread_cond_broadcast(&l->rcond);
129 }
130 pthread_mutex_unlock(&l->lock);
131 }
132
133 void
134 lock_for_write(rwlock *l)
135 {
136 pthread_mutex_lock(&l->lock);
137 l->waiting_writers++;
138 pthread_cleanup_push(waiting_writer_cleanup, l);
139 while (l->lock_count != 0)
140 pthread_cond_wait(&l->wcond, &l->lock);
141 l->lock_count = −1;
142 /*
143 * Note the pthread_cleanup_pop executes
144 * waiting_writer_cleanup.
145 */
146 pthread_cleanup_pop(1);
147 }
148
149 void
150 release_write_lock(rwlock *l)
151 {
152 pthread_mutex_lock(&l->lock);
153 l->lock_count = 0;
154 if (l->waiting_writers == 0)
155 pthread_cond_broadcast(&l->rcond);
156 else
157 pthread_cond_signal(&l->wcond);
158 pthread_mutex_unlock(&l->lock);
159 }
160
161 /*
162 * This function is called to initialize the read/write lock.
163 */
164 void
165 initialize_rwlock(rwlock *l)
166 {
167 pthread_mutex_init(&l->lock, pthread_mutexattr_default);
168 pthread_cond_init(&l->wcond, pthread_condattr_default);
169 pthread_cond_init(&l->rcond, pthread_condattr_default);
170 l->lock_count = 0;
171 l->waiting_writers = 0;
172 }
173
174 reader_thread()
175 {
176 lock_for_read(&lock);
177 pthread_cleanup_push(release_read_lock, &lock);
178 /*
179 * Thread has read lock.
180 */
181 pthread_cleanup_pop(1);
182 }
183
184 writer_thread()
185 {
186 lock_for_write(&lock);
187 pthread_cleanup_push(release_write_lock, &lock);
188 /*
189 * Thread has write lock.
190 */
191 pthread_cleanup_pop(1);
192 }
193
195 The two routines that push and pop cancellation cleanup handlers,
196 pthread_cleanup_push() and pthread_cleanup_pop(), can be thought of as
197 left and right-parentheses. They always need to be matched.
198
200 The restriction that the two routines that push and pop cancellation
201 cleanup handlers, pthread_cleanup_push() and pthread_cleanup_pop(),
202 have to appear in the same lexical scope allows for efficient macro or
203 compiler implementations and efficient storage management. A sample
204 implementation of these routines as macros might look like this:
205
206 #define pthread_cleanup_push(rtn,arg) { \
207 struct _pthread_handler_rec __cleanup_handler, **__head; \
208 __cleanup_handler.rtn = rtn; \
209 __cleanup_handler.arg = arg; \
210 (void) pthread_getspecific(_pthread_handler_key, &__head); \
211 __cleanup_handler.next = *__head; \
212 *__head = &__cleanup_handler;
213
214 #define pthread_cleanup_pop(ex) \
215 *__head = __cleanup_handler.next; \
216 if (ex) (*__cleanup_handler.rtn)(__cleanup_handler.arg); \
217 }
218
219 A more ambitious implementation of these routines might do even better
220 by allowing the compiler to note that the cancellation cleanup handler
221 is a constant and can be expanded inline.
222
223 This volume of POSIX.1‐2008 currently leaves unspecified the effect of
224 calling longjmp() from a signal handler executing in a POSIX System
225 Interfaces function. If an implementation wants to allow this and give
226 the programmer reasonable behavior, the longjmp() function has to call
227 all cancellation cleanup handlers that have been pushed but not popped
228 since the time setjmp() was called.
229
230 Consider a multi-threaded function called by a thread that uses sig‐
231 nals. If a signal were delivered to a signal handler during the opera‐
232 tion of qsort() and that handler were to call longjmp() (which, in
233 turn, did not call the cancellation cleanup handlers) the helper
234 threads created by the qsort() function would not be canceled. Instead,
235 they would continue to execute and write into the argument array even
236 though the array might have been popped off the stack.
237
238 Note that the specified cleanup handling mechanism is especially tied
239 to the C language and, while the requirement for a uniform mechanism
240 for expressing cleanup is language-independent, the mechanism used in
241 other languages may be quite different. In addition, this mechanism is
242 really only necessary due to the lack of a real exception mechanism in
243 the C language, which would be the ideal solution.
244
245 There is no notion of a cancellation cleanup-safe function. If an
246 application has no cancellation points in its signal handlers, blocks
247 any signal whose handler may have cancellation points while calling
248 async-unsafe functions, or disables cancellation while calling async-
249 unsafe functions, all functions may be safely called from cancellation
250 cleanup routines.
251
253 None.
254
256 pthread_cancel(), pthread_setcancelstate()
257
258 The Base Definitions volume of POSIX.1‐2008, <pthread.h>
259
261 Portions of this text are reprinted and reproduced in electronic form
262 from IEEE Std 1003.1, 2013 Edition, Standard for Information Technology
263 -- Portable Operating System Interface (POSIX), The Open Group Base
264 Specifications Issue 7, Copyright (C) 2013 by the Institute of Electri‐
265 cal and Electronics Engineers, Inc and The Open Group. (This is
266 POSIX.1-2008 with the 2013 Technical Corrigendum 1 applied.) In the
267 event of any discrepancy between this version and the original IEEE and
268 The Open Group Standard, the original IEEE and The Open Group Standard
269 is the referee document. The original Standard can be obtained online
270 at http://www.unix.org/online.html .
271
272 Any typographical or formatting errors that appear in this page are
273 most likely to have been introduced during the conversion of the source
274 files to man page format. To report such errors, see https://www.ker‐
275 nel.org/doc/man-pages/reporting_bugs.html .
276
277
278
279IEEE/The Open Group 2013 PTHREAD_CLEANUP_POP(3P)