1PTHREAD_CLEANUP_POP(3P)    POSIX Programmer's Manual   PTHREAD_CLEANUP_POP(3P)
2
3
4

PROLOG

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

NAME

13       pthread_cleanup_pop, pthread_cleanup_push — establish cancellation han‐
14       dlers
15

SYNOPSIS

17       #include <pthread.h>
18
19       void pthread_cleanup_pop(int execute);
20       void pthread_cleanup_push(void (*routine)(void*), void *arg);
21

DESCRIPTION

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

RETURN VALUE

58       The  pthread_cleanup_push()  and  pthread_cleanup_pop() functions shall
59       not return a value.
60

ERRORS

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

EXAMPLES

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

APPLICATION USAGE

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

RATIONALE

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

FUTURE DIRECTIONS

253       None.
254

SEE ALSO

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)
Impressum