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

RETURN VALUE

54       The  pthread_cleanup_push()  and  pthread_cleanup_pop() functions shall
55       not return a value.
56

ERRORS

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

EXAMPLES

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

APPLICATION USAGE

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

RATIONALE

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

FUTURE DIRECTIONS

260       None.
261

SEE ALSO

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