443 lines
12 KiB
HTML
443 lines
12 KiB
HTML
|
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|
<HTML><HEAD><TITLE>Man page of PTHREAD_CLEANUP_PUSH</TITLE>
|
|
</HEAD><BODY>
|
|
<H1>PTHREAD_CLEANUP_PUSH</H1>
|
|
Section: Linux Programmer's Manual (3)<BR>Updated: 2019-03-06<BR><A HREF="#index">Index</A>
|
|
<A HREF="/cgi-bin/man/man2html">Return to Main Contents</A><HR>
|
|
|
|
<A NAME="lbAB"> </A>
|
|
<H2>NAME</H2>
|
|
|
|
pthread_cleanup_push, pthread_cleanup_pop - push and pop
|
|
thread cancellation clean-up handlers
|
|
<A NAME="lbAC"> </A>
|
|
<H2>SYNOPSIS</H2>
|
|
|
|
<PRE>
|
|
<B>#include <<A HREF="file:///usr/include/pthread.h">pthread.h</A>></B>
|
|
|
|
<B>void pthread_cleanup_push(void (*</B><I>routine</I><B>)(void *),</B>
|
|
<B> void *</B><I>arg</I><B>);</B>
|
|
<B>void pthread_cleanup_pop(int </B><I>execute</I><B>);</B>
|
|
|
|
Compile and link with <I>-pthread</I>.
|
|
</PRE>
|
|
|
|
<A NAME="lbAD"> </A>
|
|
<H2>DESCRIPTION</H2>
|
|
|
|
These functions manipulate the calling thread's stack of
|
|
thread-cancellation clean-up handlers.
|
|
A clean-up handler is a function that is automatically executed
|
|
when a thread is canceled (or in various other circumstances
|
|
described below);
|
|
it might, for example, unlock a mutex so that
|
|
it becomes available to other threads in the process.
|
|
<P>
|
|
|
|
The
|
|
<B>pthread_cleanup_push</B>()
|
|
|
|
function pushes
|
|
<I>routine</I>
|
|
|
|
onto the top of the stack of clean-up handlers.
|
|
When
|
|
<I>routine</I>
|
|
|
|
is later invoked, it will be given
|
|
<I>arg</I>
|
|
|
|
as its argument.
|
|
<P>
|
|
|
|
The
|
|
<B>pthread_cleanup_pop</B>()
|
|
|
|
function removes the routine at the top of the stack of clean-up handlers,
|
|
and optionally executes it if
|
|
<I>execute</I>
|
|
|
|
is nonzero.
|
|
<P>
|
|
|
|
A cancellation clean-up handler is popped from the stack
|
|
and executed in the following circumstances:
|
|
<DL COMPACT>
|
|
<DT id="1">1.<DD>
|
|
When a thread is canceled,
|
|
all of the stacked clean-up handlers are popped and executed in
|
|
the reverse of the order in which they were pushed onto the stack.
|
|
<DT id="2">2.<DD>
|
|
When a thread terminates by calling
|
|
<B><A HREF="/cgi-bin/man/man2html?3+pthread_exit">pthread_exit</A></B>(3),
|
|
|
|
all clean-up handlers are executed as described in the preceding point.
|
|
(Clean-up handlers are
|
|
<I>not</I>
|
|
|
|
called if the thread terminates by
|
|
performing a
|
|
<I>return</I>
|
|
|
|
from the thread start function.)
|
|
<DT id="3">3.<DD>
|
|
When a thread calls
|
|
<B>pthread_cleanup_pop</B>()
|
|
|
|
with a nonzero
|
|
<I>execute</I>
|
|
|
|
argument, the top-most clean-up handler is popped and executed.
|
|
</DL>
|
|
<P>
|
|
|
|
POSIX.1 permits
|
|
<B>pthread_cleanup_push</B>()
|
|
|
|
and
|
|
<B>pthread_cleanup_pop</B>()
|
|
|
|
to be implemented as macros that expand to text
|
|
containing '<B>{</B>' and '<B>}</B>', respectively.
|
|
For this reason, the caller must ensure that calls to these
|
|
functions are paired within the same function,
|
|
and at the same lexical nesting level.
|
|
(In other words, a clean-up handler is established only
|
|
during the execution of a specified section of code.)
|
|
<P>
|
|
|
|
Calling
|
|
<B><A HREF="/cgi-bin/man/man2html?3+longjmp">longjmp</A></B>(3)
|
|
|
|
(<B><A HREF="/cgi-bin/man/man2html?3+siglongjmp">siglongjmp</A></B>(3))
|
|
|
|
produces undefined results if any call has been made to
|
|
<B>pthread_cleanup_push</B>()
|
|
|
|
or
|
|
<B>pthread_cleanup_pop</B>()
|
|
|
|
without the matching call of the pair since the jump buffer
|
|
was filled by
|
|
<B><A HREF="/cgi-bin/man/man2html?3+setjmp">setjmp</A></B>(3)
|
|
|
|
(<B><A HREF="/cgi-bin/man/man2html?3+sigsetjmp">sigsetjmp</A></B>(3)).
|
|
|
|
Likewise, calling
|
|
<B><A HREF="/cgi-bin/man/man2html?3+longjmp">longjmp</A></B>(3)
|
|
|
|
(<B><A HREF="/cgi-bin/man/man2html?3+siglongjmp">siglongjmp</A></B>(3))
|
|
|
|
from inside a clean-up handler produces undefined results
|
|
unless the jump buffer was also filled by
|
|
<B><A HREF="/cgi-bin/man/man2html?3+setjmp">setjmp</A></B>(3)
|
|
|
|
(<B><A HREF="/cgi-bin/man/man2html?3+sigsetjmp">sigsetjmp</A></B>(3))
|
|
|
|
inside the handler.
|
|
<A NAME="lbAE"> </A>
|
|
<H2>RETURN VALUE</H2>
|
|
|
|
These functions do not return a value.
|
|
<A NAME="lbAF"> </A>
|
|
<H2>ERRORS</H2>
|
|
|
|
There are no errors.
|
|
|
|
|
|
<A NAME="lbAG"> </A>
|
|
<H2>ATTRIBUTES</H2>
|
|
|
|
For an explanation of the terms used in this section, see
|
|
<B><A HREF="/cgi-bin/man/man2html?7+attributes">attributes</A></B>(7).
|
|
|
|
<TABLE BORDER>
|
|
<TR VALIGN=top><TD><B>Interface</B></TD><TD><B>Attribute</B></TD><TD><B>Value</B><BR></TD></TR>
|
|
<TR VALIGN=top><TD>
|
|
<B>pthread_cleanup_push</B>(),
|
|
|
|
<B>pthread_cleanup_pop</B>()
|
|
|
|
</TD><TD>Thread safety</TD><TD>MT-Safe<BR></TD></TR>
|
|
</TABLE>
|
|
|
|
<P>
|
|
<A NAME="lbAH"> </A>
|
|
<H2>CONFORMING TO</H2>
|
|
|
|
POSIX.1-2001, POSIX.1-2008.
|
|
<A NAME="lbAI"> </A>
|
|
<H2>NOTES</H2>
|
|
|
|
On Linux, the
|
|
<B>pthread_cleanup_push</B>()
|
|
|
|
and
|
|
<B>pthread_cleanup_pop</B>()
|
|
|
|
functions
|
|
<I>are</I>
|
|
|
|
implemented as macros that expand to text
|
|
containing '<B>{</B>' and '<B>}</B>', respectively.
|
|
This means that variables declared within the scope of
|
|
paired calls to these functions will be visible within only that scope.
|
|
<P>
|
|
|
|
POSIX.1
|
|
|
|
says that the effect of using
|
|
<I>return</I>,
|
|
|
|
<I>break</I>,
|
|
|
|
<I>continue</I>,
|
|
|
|
or
|
|
<I>goto</I>
|
|
|
|
to prematurely leave a block bracketed
|
|
<B>pthread_cleanup_push</B>()
|
|
|
|
and
|
|
<B>pthread_cleanup_pop</B>()
|
|
|
|
is undefined.
|
|
Portable applications should avoid doing this.
|
|
<A NAME="lbAJ"> </A>
|
|
<H2>EXAMPLE</H2>
|
|
|
|
The program below provides a simple example of the use of the functions
|
|
described in this page.
|
|
The program creates a thread that executes a loop bracketed by
|
|
<B>pthread_cleanup_push</B>()
|
|
|
|
and
|
|
<B>pthread_cleanup_pop</B>().
|
|
|
|
This loop increments a global variable,
|
|
<I>cnt</I>,
|
|
|
|
once each second.
|
|
Depending on what command-line arguments are supplied,
|
|
the main thread sends the other thread a cancellation request,
|
|
or sets a global variable that causes the other thread
|
|
to exit its loop and terminate normally (by doing a
|
|
<I>return</I>).
|
|
|
|
<P>
|
|
|
|
In the following shell session,
|
|
the main thread sends a cancellation request to the other thread:
|
|
<P>
|
|
|
|
|
|
|
|
$ <B>./a.out</B>
|
|
New thread started
|
|
cnt = 0
|
|
cnt = 1
|
|
Canceling thread
|
|
Called clean-up handler
|
|
Thread was canceled; cnt = 0
|
|
|
|
|
|
<P>
|
|
|
|
From the above, we see that the thread was canceled,
|
|
and that the cancellation clean-up handler was called
|
|
and it reset the value of the global variable
|
|
<I>cnt</I>
|
|
|
|
to 0.
|
|
<P>
|
|
|
|
In the next run, the main program sets a
|
|
global variable that causes other thread to terminate normally:
|
|
<P>
|
|
|
|
|
|
|
|
$ <B>./a.out x</B>
|
|
New thread started
|
|
cnt = 0
|
|
cnt = 1
|
|
Thread terminated normally; cnt = 2
|
|
|
|
|
|
<P>
|
|
|
|
From the above, we see that the clean-up handler was not executed (because
|
|
<I>cleanup_pop_arg</I>
|
|
|
|
was 0), and therefore the value of
|
|
<I>cnt</I>
|
|
|
|
was not reset.
|
|
<P>
|
|
|
|
In the next run, the main program sets a global variable that
|
|
causes the other thread to terminate normally,
|
|
and supplies a nonzero value for
|
|
<I>cleanup_pop_arg</I>:
|
|
|
|
<P>
|
|
|
|
|
|
|
|
$ <B>./a.out x 1</B>
|
|
New thread started
|
|
cnt = 0
|
|
cnt = 1
|
|
Called clean-up handler
|
|
Thread terminated normally; cnt = 0
|
|
|
|
|
|
<P>
|
|
|
|
In the above, we see that although the thread was not canceled,
|
|
the clean-up handler was executed, because the argument given to
|
|
<B>pthread_cleanup_pop</B>()
|
|
|
|
was nonzero.
|
|
<A NAME="lbAK"> </A>
|
|
<H3>Program source</H3>
|
|
|
|
|
|
|
|
#include <<A HREF="file:///usr/include/pthread.h">pthread.h</A>>
|
|
#include <<A HREF="file:///usr/include/sys/types.h">sys/types.h</A>>
|
|
#include <<A HREF="file:///usr/include/stdio.h">stdio.h</A>>
|
|
#include <<A HREF="file:///usr/include/stdlib.h">stdlib.h</A>>
|
|
#include <<A HREF="file:///usr/include/unistd.h">unistd.h</A>>
|
|
#include <<A HREF="file:///usr/include/errno.h">errno.h</A>>
|
|
<P>
|
|
#define handle_error_en(en, msg) \
|
|
<BR> do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
|
|
<P>
|
|
static int done = 0;
|
|
static int cleanup_pop_arg = 0;
|
|
static int cnt = 0;
|
|
<P>
|
|
static void
|
|
cleanup_handler(void *arg)
|
|
{
|
|
<BR> printf("Called clean-up handler\n");
|
|
<BR> cnt = 0;
|
|
}
|
|
<P>
|
|
static void *
|
|
thread_start(void *arg)
|
|
{
|
|
<BR> time_t start, curr;
|
|
<P>
|
|
<BR> printf("New thread started\n");
|
|
<P>
|
|
<BR> pthread_cleanup_push(cleanup_handler, NULL);
|
|
<P>
|
|
<BR> curr = start = time(NULL);
|
|
<P>
|
|
<BR> while (!done) {
|
|
<BR> pthread_testcancel(); /* A cancellation point */
|
|
<BR> if (curr < time(NULL)) {
|
|
<BR> curr = time(NULL);
|
|
<BR> printf("cnt = %d\n", cnt); /* A cancellation point */
|
|
<BR> cnt++;
|
|
<BR> }
|
|
<BR> }
|
|
<P>
|
|
<BR> pthread_cleanup_pop(cleanup_pop_arg);
|
|
<BR> return NULL;
|
|
}
|
|
<P>
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
<BR> pthread_t thr;
|
|
<BR> int s;
|
|
<BR> void *res;
|
|
<P>
|
|
<BR> s = pthread_create(&thr, NULL, thread_start, NULL);
|
|
<BR> if (s != 0)
|
|
<BR> handle_error_en(s, "pthread_create");
|
|
<P>
|
|
<BR> <A HREF="/cgi-bin/man/man2html?2+sleep">sleep</A>(2); /* Allow new thread to run a while */
|
|
<P>
|
|
<BR> if (argc > 1) {
|
|
<BR> if (argc > 2)
|
|
<BR> cleanup_pop_arg = atoi(argv[2]);
|
|
<BR> done = 1;
|
|
<P>
|
|
<BR> } else {
|
|
<BR> printf("Canceling thread\n");
|
|
<BR> s = pthread_cancel(thr);
|
|
<BR> if (s != 0)
|
|
<BR> handle_error_en(s, "pthread_cancel");
|
|
<BR> }
|
|
<P>
|
|
<BR> s = pthread_join(thr, &res);
|
|
<BR> if (s != 0)
|
|
<BR> handle_error_en(s, "pthread_join");
|
|
<P>
|
|
<BR> if (res == PTHREAD_CANCELED)
|
|
<BR> printf("Thread was canceled; cnt = %d\n", cnt);
|
|
<BR> else
|
|
<BR> printf("Thread terminated normally; cnt = %d\n", cnt);
|
|
<BR> exit(EXIT_SUCCESS);
|
|
}
|
|
|
|
<A NAME="lbAL"> </A>
|
|
<H2>SEE ALSO</H2>
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?3+pthread_cancel">pthread_cancel</A></B>(3),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?3+pthread_cleanup_push_defer_np">pthread_cleanup_push_defer_np</A></B>(3),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?3+pthread_setcancelstate">pthread_setcancelstate</A></B>(3),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?3+pthread_testcancel">pthread_testcancel</A></B>(3),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?7+pthreads">pthreads</A></B>(7)
|
|
|
|
<A NAME="lbAM"> </A>
|
|
<H2>COLOPHON</H2>
|
|
|
|
This page is part of release 5.05 of the Linux
|
|
<I>man-pages</I>
|
|
|
|
project.
|
|
A description of the project,
|
|
information about reporting bugs,
|
|
and the latest version of this page,
|
|
can be found at
|
|
<A HREF="https://www.kernel.org/doc/man-pages/.">https://www.kernel.org/doc/man-pages/.</A>
|
|
<P>
|
|
|
|
<HR>
|
|
<A NAME="index"> </A><H2>Index</H2>
|
|
<DL>
|
|
<DT id="4"><A HREF="#lbAB">NAME</A><DD>
|
|
<DT id="5"><A HREF="#lbAC">SYNOPSIS</A><DD>
|
|
<DT id="6"><A HREF="#lbAD">DESCRIPTION</A><DD>
|
|
<DT id="7"><A HREF="#lbAE">RETURN VALUE</A><DD>
|
|
<DT id="8"><A HREF="#lbAF">ERRORS</A><DD>
|
|
<DT id="9"><A HREF="#lbAG">ATTRIBUTES</A><DD>
|
|
<DT id="10"><A HREF="#lbAH">CONFORMING TO</A><DD>
|
|
<DT id="11"><A HREF="#lbAI">NOTES</A><DD>
|
|
<DT id="12"><A HREF="#lbAJ">EXAMPLE</A><DD>
|
|
<DL>
|
|
<DT id="13"><A HREF="#lbAK">Program source</A><DD>
|
|
</DL>
|
|
<DT id="14"><A HREF="#lbAL">SEE ALSO</A><DD>
|
|
<DT id="15"><A HREF="#lbAM">COLOPHON</A><DD>
|
|
</DL>
|
|
<HR>
|
|
This document was created by
|
|
<A HREF="/cgi-bin/man/man2html">man2html</A>,
|
|
using the manual pages.<BR>
|
|
Time: 00:05:53 GMT, March 31, 2021
|
|
</BODY>
|
|
</HTML>
|