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

NAME

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

SYNOPSIS

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

DESCRIPTION

22       The  pthread_cleanup_pop() function shall remove the routine at the top
23       of the calling  thread's  cancellation  cleanup  stack  and  optionally
24       invoke it (if execute is non-zero).
25
26       The  pthread_cleanup_push() function shall push the specified cancella‐
27       tion cleanup handler routine onto  the  calling  thread's  cancellation
28       cleanup  stack.  The  cancellation cleanup handler shall be popped from
29       the cancellation cleanup stack and invoked with the argument arg when:
30
31        *  The thread exits (that is, calls pthread_exit()).
32
33        *  The thread acts upon a cancellation request.
34
35        *  The thread calls  pthread_cleanup_pop()  with  a  non-zero  execute
36           argument.
37
38       It     is     unspecified     whether     pthread_cleanup_push()    and
39       pthread_cleanup_pop() are macros or functions. If a macro definition is
40       suppressed  in order to access an actual function, or a program defines
41       an external identifier with any of these names, the behavior  is  unde‐
42       fined.   The  application  shall ensure that they appear as statements,
43       and  in  pairs  within  the  same   lexical   scope   (that   is,   the
44       pthread_cleanup_push()  macro  may be thought to expand to a token list
45       whose first token is '{'  with  pthread_cleanup_pop()  expanding  to  a
46       token list whose last token is the corresponding '}').
47
48       The  effect  of calling longjmp() or siglongjmp() is undefined if there
49       have been any calls to pthread_cleanup_push() or  pthread_cleanup_pop()
50       made  without  the  matching call since the jump buffer was filled. The
51       effect of calling longjmp() or siglongjmp() from inside a  cancellation
52       cleanup  handler  is  also  undefined  unless  the jump buffer was also
53       filled in the cancellation cleanup handler.
54
55       The effect of the use of return, break, continue, and  goto  to  prema‐
56       turely leave a code block described by a pair of pthread_cleanup_push()
57       and pthread_cleanup_pop() functions calls is undefined.
58

RETURN VALUE

60       The pthread_cleanup_push() and  pthread_cleanup_pop()  functions  shall
61       not return a value.
62

ERRORS

64       No errors are defined.
65
66       These functions shall not return an error code of [EINTR].
67
68       The following sections are informative.
69

EXAMPLES

71       The following is an example using thread primitives to implement a can‐
72       celable, writers-priority read-write lock:
73
74
75           typedef struct {
76               pthread_mutex_t lock;
77               pthread_cond_t rcond,
78                   wcond;
79               int lock_count; /* < 0 .. Held by writer. */
80                               /* > 0 .. Held by lock_count readers. */
81                               /* = 0 .. Held by nobody. */
82               int waiting_writers; /* Count of waiting writers. */
83           } rwlock;
84
85           void
86           waiting_reader_cleanup(void *arg)
87           {
88               rwlock *l;
89
90               l = (rwlock *) arg;
91               pthread_mutex_unlock(&l->lock);
92           }
93
94           void
95           lock_for_read(rwlock *l)
96           {
97               pthread_mutex_lock(&l->lock);
98               pthread_cleanup_push(waiting_reader_cleanup, l);
99               while ((l->lock_count < 0) || (l->waiting_writers != 0))
100                   pthread_cond_wait(&l->rcond, &l->lock);
101               l->lock_count++;
102              /*
103               * Note the pthread_cleanup_pop executes
104               * waiting_reader_cleanup.
105               */
106               pthread_cleanup_pop(1);
107           }
108
109           void
110           release_read_lock(rwlock *l)
111           {
112               pthread_mutex_lock(&l->lock);
113               if (--l->lock_count == 0)
114                   pthread_cond_signal(&l->wcond);
115               pthread_mutex_unlock(&l->lock);
116           }
117
118           void
119           waiting_writer_cleanup(void *arg)
120           {
121               rwlock *l;
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. If the
127                   * lock is not held by a writer, there may be readers who
128                   * were blocked because waiting_writers was positive; they
129                   * can now be unblocked.
130                   */
131                   pthread_cond_broadcast(&l->rcond);
132               }
133               pthread_mutex_unlock(&l->lock);
134           }
135
136           void
137           lock_for_write(rwlock *l)
138           {
139               pthread_mutex_lock(&l->lock);
140               l->waiting_writers++;
141               pthread_cleanup_push(waiting_writer_cleanup, l);
142               while (l->lock_count != 0)
143                   pthread_cond_wait(&l->wcond, &l->lock);
144               l->lock_count = -1;
145              /*
146               * Note the pthread_cleanup_pop executes
147               * waiting_writer_cleanup.
148               */
149               pthread_cleanup_pop(1);
150           }
151
152           void
153           release_write_lock(rwlock *l)
154           {
155               pthread_mutex_lock(&l->lock);
156               l->lock_count = 0;
157               if (l->waiting_writers == 0)
158                   pthread_cond_broadcast(&l->rcond);
159               else
160                   pthread_cond_signal(&l->wcond);
161               pthread_mutex_unlock(&l->lock);
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           reader_thread()
178           {
179               lock_for_read(&lock);
180               pthread_cleanup_push(release_read_lock, &lock);
181              /*
182               * Thread has read lock.
183               */
184               pthread_cleanup_pop(1);
185           }
186
187           writer_thread()
188           {
189               lock_for_write(&lock);
190               pthread_cleanup_push(release_write_lock, &lock);
191              /*
192               * Thread has write lock.
193               */
194           pthread_cleanup_pop(1);
195           }
196

APPLICATION USAGE

198       The two routines that  push  and  pop  cancellation  cleanup  handlers,
199       pthread_cleanup_push()  and pthread_cleanup_pop(), can be thought of as
200       left and right-parentheses. They always need to be matched.
201

RATIONALE

203       The restriction that the two routines that push  and  pop  cancellation
204       cleanup  handlers,  pthread_cleanup_push()  and  pthread_cleanup_pop(),
205       have to appear in the same lexical scope allows for efficient macro  or
206       compiler  implementations  and  efficient  storage management. A sample
207       implementation of these routines as macros might look like this:
208
209
210           #define pthread_cleanup_push(rtn,arg) { \
211               struct _pthread_handler_rec __cleanup_handler, **__head; \
212               __cleanup_handler.rtn = rtn; \
213               __cleanup_handler.arg = arg; \
214               (void) pthread_getspecific(_pthread_handler_key, &__head); \
215               __cleanup_handler.next = *__head; \
216               *__head = &__cleanup_handler;
217
218           #define pthread_cleanup_pop(ex) \
219               *__head = __cleanup_handler.next; \
220               if (ex) (*__cleanup_handler.rtn)(__cleanup_handler.arg); \
221           }
222
223       A more ambitious implementation of these routines might do even  better
224       by  allowing the compiler to note that the cancellation cleanup handler
225       is a constant and can be expanded inline.
226
227       This volume of POSIX.1‐2017 currently leaves unspecified the effect  of
228       calling  longjmp()  from  a  signal handler executing in a POSIX System
229       Interfaces function.  If an implementation wants to allow this and give
230       the  programmer reasonable behavior, the longjmp() function has to call
231       all cancellation cleanup handlers that have been pushed but not  popped
232       since the time setjmp() was called.
233
234       Consider  a  multi-threaded  function called by a thread that uses sig‐
235       nals. If a signal were delivered to a signal handler during the  opera‐
236       tion  of  qsort()  and  that  handler were to call longjmp() (which, in
237       turn, did not  call  the  cancellation  cleanup  handlers)  the  helper
238       threads created by the qsort() function would not be canceled. Instead,
239       they would continue to execute and write into the argument  array  even
240       though the array might have been popped off the stack.
241
242       Note  that  the specified cleanup handling mechanism is especially tied
243       to the C language and, while the requirement for  a  uniform  mechanism
244       for  expressing  cleanup is language-independent, the mechanism used in
245       other languages may be quite different. In addition, this mechanism  is
246       really  only necessary due to the lack of a real exception mechanism in
247       the C language, which would be the ideal solution.
248
249       There is no notion of  a  cancellation  cleanup-safe  function.  If  an
250       application  has  no cancellation points in its signal handlers, blocks
251       any signal whose handler may have  cancellation  points  while  calling
252       async-unsafe  functions,  or disables cancellation while calling async-
253       unsafe functions, all functions may be safely called from  cancellation
254       cleanup routines.
255

FUTURE DIRECTIONS

257       None.
258

SEE ALSO

260       pthread_cancel(), pthread_setcancelstate()
261
262       The Base Definitions volume of POSIX.1‐2017, <pthread.h>
263
265       Portions  of  this text are reprinted and reproduced in electronic form
266       from IEEE Std 1003.1-2017, Standard for Information Technology --  Por‐
267       table  Operating System Interface (POSIX), The Open Group Base Specifi‐
268       cations Issue 7, 2018 Edition, Copyright (C) 2018 by the  Institute  of
269       Electrical  and  Electronics Engineers, Inc and The Open Group.  In the
270       event of any discrepancy between this version and the original IEEE and
271       The  Open Group Standard, the original IEEE and The Open Group Standard
272       is the referee document. The original Standard can be  obtained  online
273       at http://www.opengroup.org/unix/online.html .
274
275       Any  typographical  or  formatting  errors that appear in this page are
276       most likely to have been introduced during the conversion of the source
277       files  to  man page format. To report such errors, see https://www.ker
278       nel.org/doc/man-pages/reporting_bugs.html .
279
280
281
282IEEE/The Open Group                  2017              PTHREAD_CLEANUP_POP(3P)
Impressum