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

NAME

6       pthread_cleanup_pop, pthread_cleanup_push - establish cancellation han‐
7       dlers
8

SYNOPSIS

10       #include <pthread.h>
11
12       void pthread_cleanup_pop(int execute);
13       void pthread_cleanup_push(void (*routine)(void*), void *arg);
14
15

DESCRIPTION

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

RETURN VALUE

48       The pthread_cleanup_push() and  pthread_cleanup_pop()  functions  shall
49       not return a value.
50

ERRORS

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

EXAMPLES

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

APPLICATION USAGE

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

RATIONALE

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

FUTURE DIRECTIONS

254       None.
255

SEE ALSO

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