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