pthread_cleanup_pop.3p (9817B)
- '\" et
- .TH PTHREAD_CLEANUP_POP "3P" 2017 "IEEE/The Open Group" "POSIX Programmer's Manual"
- .\"
- .SH PROLOG
- This manual page is part of the POSIX Programmer's Manual.
- The Linux implementation of this interface may differ (consult
- the corresponding Linux manual page for details of Linux behavior),
- or the interface may not be implemented on Linux.
- .\"
- .SH NAME
- pthread_cleanup_pop,
- pthread_cleanup_push
- \(em establish cancellation handlers
- .SH SYNOPSIS
- .LP
- .nf
- #include <pthread.h>
- .P
- void pthread_cleanup_pop(int \fIexecute\fP);
- void pthread_cleanup_push(void (*\fIroutine\fP)(void*), void *\fIarg\fP);
- .fi
- .SH DESCRIPTION
- The
- \fIpthread_cleanup_pop\fR()
- function shall remove the routine at the top of the calling thread's
- cancellation cleanup stack and optionally invoke it (if
- .IR execute
- is non-zero).
- .P
- The
- \fIpthread_cleanup_push\fR()
- function shall push the specified cancellation cleanup handler
- .IR routine
- onto the calling thread's cancellation cleanup stack. The cancellation
- cleanup handler shall be popped from the cancellation cleanup stack and
- invoked with the argument
- .IR arg
- when:
- .IP " *" 4
- The thread exits (that is, calls
- \fIpthread_exit\fR()).
- .IP " *" 4
- The thread acts upon a cancellation request.
- .IP " *" 4
- The thread calls
- \fIpthread_cleanup_pop\fR()
- with a non-zero
- .IR execute
- argument.
- .P
- It is unspecified whether
- \fIpthread_cleanup_push\fR()
- and
- \fIpthread_cleanup_pop\fR()
- are macros or functions. If a macro definition is suppressed in order
- to access an actual function, or a program defines an external
- identifier with any of these names, the behavior is undefined.
- The application shall ensure that they appear as statements,
- and in pairs within the same lexical scope (that is, the
- \fIpthread_cleanup_push\fR()
- macro may be thought to expand to a token list whose first token is
- .BR '{'
- with
- \fIpthread_cleanup_pop\fR()
- expanding to a token list whose last token is the corresponding
- .BR '}' ).
- .P
- The effect of calling
- \fIlongjmp\fR()
- or
- \fIsiglongjmp\fR()
- is undefined if there have been any calls to
- \fIpthread_cleanup_push\fR()
- or
- \fIpthread_cleanup_pop\fR()
- made without the matching call since the jump buffer was filled. The
- effect of calling
- \fIlongjmp\fR()
- or
- \fIsiglongjmp\fR()
- from inside a cancellation cleanup handler is also undefined unless the
- jump buffer was also filled in the cancellation cleanup handler.
- .P
- The effect of the use of
- .BR return ,
- .BR break ,
- .BR continue ,
- and
- .BR goto
- to prematurely leave a code block described by a pair of
- \fIpthread_cleanup_push\fR()
- and
- \fIpthread_cleanup_pop\fR()
- functions calls is undefined.
- .SH "RETURN VALUE"
- The
- \fIpthread_cleanup_push\fR()
- and
- \fIpthread_cleanup_pop\fR()
- functions shall not return a value.
- .SH ERRORS
- No errors are defined.
- .P
- These functions shall not return an error code of
- .BR [EINTR] .
- .LP
- .IR "The following sections are informative."
- .SH EXAMPLES
- The following is an example using thread primitives to implement a
- cancelable, writers-priority read-write lock:
- .sp
- .RS 4
- .nf
- typedef struct {
- pthread_mutex_t lock;
- pthread_cond_t rcond,
- wcond;
- int lock_count; /* < 0 .. Held by writer. */
- /* > 0 .. Held by lock_count readers. */
- /* = 0 .. Held by nobody. */
- int waiting_writers; /* Count of waiting writers. */
- } rwlock;
- .P
- void
- waiting_reader_cleanup(void *arg)
- {
- rwlock *l;
- .P
- l = (rwlock *) arg;
- pthread_mutex_unlock(&l->lock);
- }
- .P
- void
- lock_for_read(rwlock *l)
- {
- pthread_mutex_lock(&l->lock);
- pthread_cleanup_push(waiting_reader_cleanup, l);
- while ((l->lock_count < 0) || (l->waiting_writers != 0))
- pthread_cond_wait(&l->rcond, &l->lock);
- l->lock_count++;
- /*
- * Note the pthread_cleanup_pop executes
- * waiting_reader_cleanup.
- */
- pthread_cleanup_pop(1);
- }
- .P
- void
- release_read_lock(rwlock *l)
- {
- pthread_mutex_lock(&l->lock);
- if (--l->lock_count == 0)
- pthread_cond_signal(&l->wcond);
- pthread_mutex_unlock(&l->lock);
- }
- .P
- void
- waiting_writer_cleanup(void *arg)
- {
- rwlock *l;
- .P
- l = (rwlock *) arg;
- if ((--l->waiting_writers == 0) && (l->lock_count >= 0)) {
- /*
- * This only happens if we have been canceled. If the
- * lock is not held by a writer, there may be readers who
- * were blocked because waiting_writers was positive; they
- * can now be unblocked.
- */
- pthread_cond_broadcast(&l->rcond);
- }
- pthread_mutex_unlock(&l->lock);
- }
- .P
- void
- lock_for_write(rwlock *l)
- {
- pthread_mutex_lock(&l->lock);
- l->waiting_writers++;
- pthread_cleanup_push(waiting_writer_cleanup, l);
- while (l->lock_count != 0)
- pthread_cond_wait(&l->wcond, &l->lock);
- l->lock_count = -1;
- /*
- * Note the pthread_cleanup_pop executes
- * waiting_writer_cleanup.
- */
- pthread_cleanup_pop(1);
- }
- .P
- void
- release_write_lock(rwlock *l)
- {
- pthread_mutex_lock(&l->lock);
- l->lock_count = 0;
- if (l->waiting_writers == 0)
- pthread_cond_broadcast(&l->rcond);
- else
- pthread_cond_signal(&l->wcond);
- pthread_mutex_unlock(&l->lock);
- }
- .P
- /*
- * This function is called to initialize the read/write lock.
- */
- void
- initialize_rwlock(rwlock *l)
- {
- pthread_mutex_init(&l->lock, pthread_mutexattr_default);
- pthread_cond_init(&l->wcond, pthread_condattr_default);
- pthread_cond_init(&l->rcond, pthread_condattr_default);
- l->lock_count = 0;
- l->waiting_writers = 0;
- }
- .P
- reader_thread()
- {
- lock_for_read(&lock);
- pthread_cleanup_push(release_read_lock, &lock);
- /*
- * Thread has read lock.
- */
- pthread_cleanup_pop(1);
- }
- .P
- writer_thread()
- {
- lock_for_write(&lock);
- pthread_cleanup_push(release_write_lock, &lock);
- /*
- * Thread has write lock.
- */
- pthread_cleanup_pop(1);
- }
- .fi
- .P
- .RE
- .SH "APPLICATION USAGE"
- The two routines that push and pop cancellation cleanup handlers,
- \fIpthread_cleanup_push\fR()
- and
- \fIpthread_cleanup_pop\fR(),
- can be thought of as left and right-parentheses. They always need to
- be matched.
- .SH RATIONALE
- The restriction that the two routines that push and pop
- cancellation cleanup handlers,
- \fIpthread_cleanup_push\fR()
- and
- \fIpthread_cleanup_pop\fR(),
- have to appear in the same lexical scope allows for efficient macro or
- compiler implementations and efficient storage management. A sample
- implementation of these routines as macros might look like this:
- .sp
- .RS 4
- .nf
- #define pthread_cleanup_push(rtn,arg) { \e
- struct _pthread_handler_rec __cleanup_handler, **__head; \e
- __cleanup_handler.rtn = rtn; \e
- __cleanup_handler.arg = arg; \e
- (void) pthread_getspecific(_pthread_handler_key, &__head); \e
- __cleanup_handler.next = *__head; \e
- *__head = &__cleanup_handler;
- .P
- #define pthread_cleanup_pop(ex) \e
- *__head = __cleanup_handler.next; \e
- if (ex) (*__cleanup_handler.rtn)(__cleanup_handler.arg); \e
- }
- .fi
- .P
- .RE
- .P
- A more ambitious implementation of these routines might do even better
- by allowing the compiler to note that the
- cancellation cleanup handler is a constant and can be expanded inline.
- .P
- This volume of POSIX.1\(hy2017 currently leaves unspecified the effect of calling
- \fIlongjmp\fR()
- from a signal handler executing in a POSIX System Interfaces function.
- If an implementation wants to allow this and give the programmer
- reasonable behavior, the
- \fIlongjmp\fR()
- function has to call all cancellation cleanup handlers that have been
- pushed but not popped since the time
- \fIsetjmp\fR()
- was called.
- .P
- Consider a multi-threaded function called by a thread that uses
- signals. If a signal were delivered to a signal handler during the
- operation of
- \fIqsort\fR()
- and that handler were to call
- \fIlongjmp\fR()
- (which, in turn, did
- .IR not
- call the cancellation cleanup handlers) the helper threads created by
- the
- \fIqsort\fR()
- function would not be canceled. Instead, they would continue to execute
- and write into the argument array even though the array might have been
- popped off the stack.
- .P
- Note that the specified cleanup handling mechanism is especially tied
- to the C language and, while the requirement for a uniform mechanism
- for expressing cleanup is language-independent, the mechanism used in
- other languages may be quite different. In addition, this mechanism is
- really only necessary due to the lack of a real exception mechanism in
- the C language, which would be the ideal solution.
- .P
- There is no notion of a cancellation cleanup-safe function. If an
- application has no cancellation points in its signal handlers, blocks
- any signal whose handler may have cancellation points while calling
- async-unsafe functions, or disables cancellation while calling
- async-unsafe functions, all functions may be safely called from
- cancellation cleanup routines.
- .SH "FUTURE DIRECTIONS"
- None.
- .SH "SEE ALSO"
- .IR "\fIpthread_cancel\fR\^(\|)",
- .IR "\fIpthread_setcancelstate\fR\^(\|)"
- .P
- The Base Definitions volume of POSIX.1\(hy2017,
- .IR "\fB<pthread.h>\fP"
- .\"
- .SH COPYRIGHT
- Portions of this text are reprinted and reproduced in electronic form
- from IEEE Std 1003.1-2017, Standard for Information Technology
- -- Portable Operating System Interface (POSIX), The Open Group Base
- Specifications Issue 7, 2018 Edition,
- Copyright (C) 2018 by the Institute of
- Electrical and Electronics Engineers, Inc and The Open Group.
- In the event of any discrepancy between this version and the original IEEE and
- The Open Group Standard, the original IEEE and The Open Group Standard
- is the referee document. The original Standard can be obtained online at
- http://www.opengroup.org/unix/online.html .
- .PP
- Any typographical or formatting errors that appear
- in this page are most likely
- to have been introduced during the conversion of the source files to
- man page format. To report such errors, see
- https://www.kernel.org/doc/man-pages/reporting_bugs.html .