man-pages/man3/pthread_cleanup_push.3.html
2021-03-31 01:06:50 +01:00

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">&nbsp;</A>
<H2>NAME</H2>
pthread_cleanup_push, pthread_cleanup_pop - push and pop
thread cancellation clean-up handlers
<A NAME="lbAC">&nbsp;</A>
<H2>SYNOPSIS</H2>
<PRE>
<B>#include &lt;<A HREF="file:///usr/include/pthread.h">pthread.h</A>&gt;</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">&nbsp;</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">&nbsp;</A>
<H2>RETURN VALUE</H2>
These functions do not return a value.
<A NAME="lbAF">&nbsp;</A>
<H2>ERRORS</H2>
There are no errors.
<A NAME="lbAG">&nbsp;</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">&nbsp;</A>
<H2>CONFORMING TO</H2>
POSIX.1-2001, POSIX.1-2008.
<A NAME="lbAI">&nbsp;</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">&nbsp;</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">&nbsp;</A>
<H3>Program source</H3>
#include &lt;<A HREF="file:///usr/include/pthread.h">pthread.h</A>&gt;
#include &lt;<A HREF="file:///usr/include/sys/types.h">sys/types.h</A>&gt;
#include &lt;<A HREF="file:///usr/include/stdio.h">stdio.h</A>&gt;
#include &lt;<A HREF="file:///usr/include/stdlib.h">stdlib.h</A>&gt;
#include &lt;<A HREF="file:///usr/include/unistd.h">unistd.h</A>&gt;
#include &lt;<A HREF="file:///usr/include/errno.h">errno.h</A>&gt;
<P>
#define handle_error_en(en, msg) \
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;do&nbsp;{&nbsp;errno&nbsp;=&nbsp;en;&nbsp;perror(msg);&nbsp;exit(EXIT_FAILURE);&nbsp;}&nbsp;while&nbsp;(0)
<P>
static int done = 0;
static int cleanup_pop_arg = 0;
static int cnt = 0;
<P>
static void
cleanup_handler(void *arg)
{
<BR>&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;Called&nbsp;clean-up&nbsp;handler\n&quot;);
<BR>&nbsp;&nbsp;&nbsp;&nbsp;cnt&nbsp;=&nbsp;0;
}
<P>
static void *
thread_start(void *arg)
{
<BR>&nbsp;&nbsp;&nbsp;&nbsp;time_t&nbsp;start,&nbsp;curr;
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;New&nbsp;thread&nbsp;started\n&quot;);
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;pthread_cleanup_push(cleanup_handler,&nbsp;NULL);
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;curr&nbsp;=&nbsp;start&nbsp;=&nbsp;time(NULL);
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;while&nbsp;(!done)&nbsp;{
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_testcancel();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;A&nbsp;cancellation&nbsp;point&nbsp;*/
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(curr&nbsp;&lt;&nbsp;time(NULL))&nbsp;{
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;curr&nbsp;=&nbsp;time(NULL);
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;cnt&nbsp;=&nbsp;%d\n&quot;,&nbsp;cnt);&nbsp;&nbsp;/*&nbsp;A&nbsp;cancellation&nbsp;point&nbsp;*/
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cnt++;
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
<BR>&nbsp;&nbsp;&nbsp;&nbsp;}
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;pthread_cleanup_pop(cleanup_pop_arg);
<BR>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;NULL;
}
<P>
int
main(int argc, char *argv[])
{
<BR>&nbsp;&nbsp;&nbsp;&nbsp;pthread_t&nbsp;thr;
<BR>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;s;
<BR>&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;*res;
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;s&nbsp;=&nbsp;pthread_create(&amp;thr,&nbsp;NULL,&nbsp;thread_start,&nbsp;NULL);
<BR>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(s&nbsp;!=&nbsp;0)
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;handle_error_en(s,&nbsp;&quot;pthread_create&quot;);
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;<A HREF="/cgi-bin/man/man2html?2+sleep">sleep</A>(2);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Allow&nbsp;new&nbsp;thread&nbsp;to&nbsp;run&nbsp;a&nbsp;while&nbsp;*/
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(argc&nbsp;&gt;&nbsp;1)&nbsp;{
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(argc&nbsp;&gt;&nbsp;2)
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cleanup_pop_arg&nbsp;=&nbsp;atoi(argv[2]);
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;done&nbsp;=&nbsp;1;
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;Canceling&nbsp;thread\n&quot;);
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s&nbsp;=&nbsp;pthread_cancel(thr);
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(s&nbsp;!=&nbsp;0)
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;handle_error_en(s,&nbsp;&quot;pthread_cancel&quot;);
<BR>&nbsp;&nbsp;&nbsp;&nbsp;}
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;s&nbsp;=&nbsp;pthread_join(thr,&nbsp;&amp;res);
<BR>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(s&nbsp;!=&nbsp;0)
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;handle_error_en(s,&nbsp;&quot;pthread_join&quot;);
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(res&nbsp;==&nbsp;PTHREAD_CANCELED)
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;Thread&nbsp;was&nbsp;canceled;&nbsp;cnt&nbsp;=&nbsp;%d\n&quot;,&nbsp;cnt);
<BR>&nbsp;&nbsp;&nbsp;&nbsp;else
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;Thread&nbsp;terminated&nbsp;normally;&nbsp;cnt&nbsp;=&nbsp;%d\n&quot;,&nbsp;cnt);
<BR>&nbsp;&nbsp;&nbsp;&nbsp;exit(EXIT_SUCCESS);
}
<A NAME="lbAL">&nbsp;</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">&nbsp;</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">&nbsp;</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>