diff options
Diffstat (limited to 'man-pages-posix-2013/man3p/pthread_cleanup_pop.3p')
-rw-r--r-- | man-pages-posix-2013/man3p/pthread_cleanup_pop.3p | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/man-pages-posix-2013/man3p/pthread_cleanup_pop.3p b/man-pages-posix-2013/man3p/pthread_cleanup_pop.3p new file mode 100644 index 0000000..19c80c6 --- /dev/null +++ b/man-pages-posix-2013/man3p/pthread_cleanup_pop.3p @@ -0,0 +1,335 @@ +'\" et +.TH PTHREAD_CLEANUP_POP "3P" 2013 "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 +These functions may be implemented as macros. 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 +\fB +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 = \(mi1; + /* + * 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 \fR +.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 +\fB +#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 \fR +.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\(hy2008 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\(hy2008, +.IR "\fB<pthread.h>\fP" +.SH COPYRIGHT +Portions of this text are reprinted and reproduced in electronic form +from IEEE Std 1003.1, 2013 Edition, Standard for Information Technology +-- Portable Operating System Interface (POSIX), The Open Group Base +Specifications Issue 7, Copyright (C) 2013 by the Institute of +Electrical and Electronics Engineers, Inc and The Open Group. +(This is POSIX.1-2008 with the 2013 Technical Corrigendum 1 applied.) 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.unix.org/online.html . + +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 . |