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
12 pthread_cleanup_pop, pthread_cleanup_push - establish cancellation han‐
13 dlers
14
16 #include <pthread.h>
17
18 void pthread_cleanup_pop(int execute);
19 void pthread_cleanup_push(void (*routine)(void*), void *arg);
20
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 argu‐
37 ment.
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
54 The pthread_cleanup_push() and pthread_cleanup_pop() functions shall
55 not return a value.
56
58 No errors are defined.
59
60 These functions shall not return an error code of [EINTR].
61
62 The following sections are informative.
63
65 The following is an example using thread primitives to implement a can‐
66 celable, writers-priority read-write lock:
67
68
69 typedef struct {
70 pthread_mutex_t lock;
71 pthread_cond_t rcond,
72 wcond;
73 int lock_count; /* < 0 .. Held by writer. */
74 /* > 0 .. Held by lock_count readers. */
75 /* = 0 .. Held by nobody. */
76 int waiting_writers; /* Count of waiting writers. */
77 } rwlock;
78
79
80 void
81 waiting_reader_cleanup(void *arg)
82 {
83 rwlock *l;
84
85
86 l = (rwlock *) arg;
87 pthread_mutex_unlock(&l->lock);
88 }
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
107 void
108 release_read_lock(rwlock *l)
109 {
110 pthread_mutex_lock(&l->lock);
111 if (--l->lock_count == 0)
112 pthread_cond_signal(&l->wcond);
113 pthread_mutex_unlock(l);
114 }
115
116
117 void
118 waiting_writer_cleanup(void *arg)
119 {
120 rwlock *l;
121
122
123 l = (rwlock *) arg;
124 if ((--l->waiting_writers == 0) && (l->lock_count >= 0)) {
125 /*
126 * This only happens if we have been canceled.
127 */
128 pthread_cond_broadcast(&l->wcond);
129 }
130 pthread_mutex_unlock(&l->lock);
131 }
132
133
134 void
135 lock_for_write(rwlock *l)
136 {
137 pthread_mutex_lock(&l->lock);
138 l->waiting_writers++;
139 pthread_cleanup_push(waiting_writer_cleanup, l);
140 while (l->lock_count != 0)
141 pthread_cond_wait(&l->wcond, &l->lock);
142 l->lock_count = -1;
143 /*
144 * Note the pthread_cleanup_pop executes
145 * waiting_writer_cleanup.
146 */
147 pthread_cleanup_pop(1);
148 }
149
150
151 void
152 release_write_lock(rwlock *l)
153 {
154 pthread_mutex_lock(&l->lock);
155 l->lock_count = 0;
156 if (l->waiting_writers == 0)
157 pthread_cond_broadcast(&l->rcond)
158 else
159 pthread_cond_signal(&l->wcond);
160 pthread_mutex_unlock(&l->lock);
161 }
162
163
164 /*
165 * This function is called to initialize the read/write lock.
166 */
167 void
168 initialize_rwlock(rwlock *l)
169 {
170 pthread_mutex_init(&l->lock, pthread_mutexattr_default);
171 pthread_cond_init(&l->wcond, pthread_condattr_default);
172 pthread_cond_init(&l->rcond, pthread_condattr_default);
173 l->lock_count = 0;
174 l->waiting_writers = 0;
175 }
176
177
178 reader_thread()
179 {
180 lock_for_read(&lock);
181 pthread_cleanup_push(release_read_lock, &lock);
182 /*
183 * Thread has read lock.
184 */
185 pthread_cleanup_pop(1);
186 }
187
188
189 writer_thread()
190 {
191 lock_for_write(&lock);
192 pthread_cleanup_push(release_write_lock, &lock);
193 /*
194 * Thread has write lock.
195 */
196 pthread_cleanup_pop(1);
197 }
198
200 The two routines that push and pop cancellation cleanup handlers,
201 pthread_cleanup_push() and pthread_cleanup_pop(), can be thought of as
202 left and right parentheses. They always need to be matched.
203
205 The restriction that the two routines that push and pop cancellation
206 cleanup handlers, pthread_cleanup_push() and pthread_cleanup_pop(),
207 have to appear in the same lexical scope allows for efficient macro or
208 compiler implementations and efficient storage management. A sample
209 implementation of these routines as macros might look like this:
210
211
212 #define pthread_cleanup_push(rtn,arg) { \
213 struct _pthread_handler_rec __cleanup_handler, **__head; \
214 __cleanup_handler.rtn = rtn; \
215 __cleanup_handler.arg = arg; \
216 (void) pthread_getspecific(_pthread_handler_key, &__head); \
217 __cleanup_handler.next = *__head; \
218 *__head = &__cleanup_handler;
219
220
221 #define pthread_cleanup_pop(ex) \
222 *__head = __cleanup_handler.next; \
223 if (ex) (*__cleanup_handler.rtn)(__cleanup_handler.arg); \
224 }
225
226 A more ambitious implementation of these routines might do even better
227 by allowing the compiler to note that the cancellation cleanup handler
228 is a constant and can be expanded inline.
229
230 This volume of IEEE Std 1003.1-2001 currently leaves unspecified the
231 effect of calling longjmp() from a signal handler executing in a POSIX
232 System Interfaces function. If an implementation wants to allow this
233 and give the programmer reasonable behavior, the longjmp() function has
234 to call all cancellation cleanup handlers that have been pushed but not
235 popped since the time setjmp() was called.
236
237 Consider a multi-threaded function called by a thread that uses sig‐
238 nals. If a signal were delivered to a signal handler during the opera‐
239 tion of qsort() and that handler were to call longjmp() (which, in
240 turn, did not call the cancellation cleanup handlers) the helper
241 threads created by the qsort() function would not be canceled.
242 Instead, they would continue to execute and write into the argument
243 array even though the array might have been popped off the stack.
244
245 Note that the specified cleanup handling mechanism is especially tied
246 to the C language and, while the requirement for a uniform mechanism
247 for expressing cleanup is language-independent, the mechanism used in
248 other languages may be quite different. In addition, this mechanism is
249 really only necessary due to the lack of a real exception mechanism in
250 the C language, which would be the ideal solution.
251
252 There is no notion of a cancellation cleanup-safe function. If an
253 application has no cancellation points in its signal handlers, blocks
254 any signal whose handler may have cancellation points while calling
255 async-unsafe functions, or disables cancellation while calling async-
256 unsafe functions, all functions may be safely called from cancellation
257 cleanup routines.
258
260 None.
261
263 pthread_cancel(), pthread_setcancelstate(), the Base Definitions volume
264 of IEEE Std 1003.1-2001, <pthread.h>
265
267 Portions of this text are reprinted and reproduced in electronic form
268 from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology
269 -- Portable Operating System Interface (POSIX), The Open Group Base
270 Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of
271 Electrical and Electronics Engineers, Inc and The Open Group. In the
272 event of any discrepancy between this version and the original IEEE and
273 The Open Group Standard, the original IEEE and The Open Group Standard
274 is the referee document. The original Standard can be obtained online
275 at http://www.opengroup.org/unix/online.html .
276
277
278
279IEEE/The Open Group 2003 PTHREAD_CLEANUP_POP(3P)