public inbox for linux-man@vger.kernel.org
 help / color / mirror / Atom feed
From: Loic Domaigne <tech-Z4JMKDdsf89Wk0Htik3J/w@public.gmane.org>
To: mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
Cc: linux-man-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	josv-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org,
	Bert Wesarg <bert.wesarg-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>,
	Karsten Weiss
	<K.Weiss-Pt+Xe7GJXK+P2YhJcF5u+nqWYbMAw+HU@public.gmane.org>
Subject: Re: For review: pthread_cleanup_push.3
Date: Sat, 22 Nov 2008 08:17:23 +0100	[thread overview]
Message-ID: <4927B203.3000702@domaigne.com> (raw)
In-Reply-To: <cfd18e0f0811140919g11e625a2i8546b3296d008dce-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

Hi Michael,

the last review for today.

Bye for now,
Loïc.
--

> .\" Copyright (c) 2008 Linux Foundation, written by Michael Kerrisk
> .\"     <mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> .\"
> .\" Permission is granted to make and distribute verbatim copies of this
> .\" manual provided the copyright notice and this permission notice are
> .\" preserved on all copies.
> .\"
> .\" Permission is granted to copy and distribute modified versions of this
> .\" manual under the conditions for verbatim copying, provided that the
> .\" entire resulting derived work is distributed under the terms of a
> .\" permission notice identical to this one.
> .\"
> .\" Since the Linux kernel and libraries are constantly changing, this
> .\" manual page may be incorrect or out-of-date.  The author(s) assume no
> .\" responsibility for errors or omissions, or for damages resulting from
> .\" the use of the information contained herein.  The author(s) may not
> .\" have taken the same level of care in the production of this manual,
> .\" which is licensed free of charge, as they might when working
> .\" professionally.
> .\"
> .\" Formatted or processed versions of this manual, if unaccompanied by
> .\" the source, must acknowledge the copyright and authors of this work.
> .\"
> .TH PTHREAD_CLEANUP_PUSH 3 2008-11-14 "Linux" "Linux Programmer's Manual"
> .SH NAME
> pthread_cleanup_push, pthread_cleanup_pop \- push and pop
> thread cancellation clean-up handlers
> .SH SYNOPSIS
> .nf
> .B #include <pthread.h>
> 
> .BI "void pthread_cleanup_push(void (*" routine ")(void *),"
> .BI "                          void *" arg );
> .BI "void pthread_cleanup_pop(int " execute );
> .sp
> Compile and link with \fI\-pthread\fP.
> .SH DESCRIPTION
> 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.
> 
> The
> .BR pthread_cleanup_push ()
> function pushes
> .I routine
> onto the top of the stack of clean-up handlers.
> When
> .I routine
> is later invoked, it will be given
> .I arg
> as its argument.
> 
> The
> .BR pthread_cleanup_pop ()
> function removes the routine at the top of the stack of clean-up handlers,
> and optionally executes it if
> .I execute
> is non-zero.
> 
> A cancellation clean-up handler is popped from the stack
> and executed in the following circumstances:
> .IP 1. 3
> 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.
> .IP 2.
> When a thread terminates by calling
> .BR pthread_exit (3),
> all clean-up handlers are executed as described in the preceding point.
> (Clean-up handlers are \fInot\fP called if the thread terminates by
> performing a
> .I return
> from the thread start function.)

Generally speaking, it is left to the implementation to call or not
clean-up handlers when a thread returns from the start function.

The behavior you are describing is Linux specific; so perhaps you should 
put this in the NOTE, in the same way that you mentioned that 
pthread_cleanup_{push/pop} are macro on Gnu/Linux.

> .IP 3.
> When a thread calls
> .BR pthread_cleanup_pop ()
> with a non-zero
> .I execute
> argument, the top-most clean-up handler is popped and executed.
> .PP
> POSIX.1 permits
> .BR pthread_cleanup_push ()
> and
> .BR pthread_cleanup_pop ()
> to be implemented as macros that expand to text
> containing \(aq\fB{\fP\(aq and \(aq\fB}\fP\(aq, 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 only established
> during the execution of a specified section of code.)
> 
> Calling
> .BR longjmp (3)
> .RB ( siglongjmp (3))
> produces undefined results if any call has been made to
> .BR pthread_cleanup_push ()
> or
> .BR pthread_cleanup_pop ()
> without the matching call of the pair since the jump buffer
> was filled by
> .BR setjmp (3)
> .RB ( sigsetjmp (3)).
> Likewise, calling
> .BR longjmp (3)
> .RB ( siglongjmp (3))
> from inside a clean-up handler produces undefined results
> unless the jump buffer was also filled by
> .BR setjmp (3)
> .RB ( sigsetjmp (3))
> inside the handler.
> .SH RETURN VALUE
> These functions do not return a value.
> .SH ERRORS
> There are no errors.
> .\" SH VERSIONS
> .\" Available since glibc 2.0
> .SH CONFORMING TO
> POSIX.1-2001.
> .SH NOTES
> On Linux, the
> .BR pthread_cleanup_push ()
> and
> .BR pthread_cleanup_pop ()
> functions \fIare\fP implemented as macros that expand to text
> containing \(aq\fB{\fP\(aq and \(aq\fB}\fP\(aq, respectively.
> This means that variables declared within the scope of
> paired calls to these functions will only be visible within that scope.
> .SH EXAMPLE
> 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
> .BR pthread_cleanup_push ()
> and
> .BR pthread_cleanup_pop ().
> This loop executes a global variable,
> .IR cnt ,
> once each second.

s/executes/increments/

> 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
> .IR return ).
> 
> In the following shell session,
> the main thread sends a cancellation request to the other thread:
> 
> .in +4n
> .nf
> $ \fB./a.out\fP
> New thread started
> cnt = 0
> cnt = 1
> Canceling thread
> Called clean-up handler
> Thread was canceled; cnt = 0
> .fi
> .in
> 
>>From the above, we see that the thread was canceled,

garbage '>' ?

> and that the cancellation clean-up handler was called
> and it reset the value of the global variable
> .I cnt
> to 0.
> 
> In the next run, the main program sets a
> global variable that causes other thread to terminate normally:
> 
> .in +4n
> .nf
> $ \fB./a.out x\fP
> New thread started
> cnt = 0
> cnt = 1
> Thread terminated normally; cnt = 2
> .fi
> .in
> 
>>From the above, we see that the clean-up handler was not executed (because

garbage '>' ?

> .I cleanup_pop_arg
> was 0), and therefore the value of
> .I cnt
> was not reset.
> 
> In the next run, the main program sets a global variable that
> causes the other thread to terminate normally,
> and supplies a non-zero value for
> .IR cleanup_pop_arg :
> 
> .in +4n
> .nf
> $ \fB./a.out x 1\fP
> New thread started
> cnt = 0
> cnt = 1
> Called clean-up handler
> Thread terminated normally; cnt = 0
> .fi
> .in
> 
> In the above, we see that although the thread was not canceled,
> the clean-up handler was executed, because the argument given to
> .BR pthread_cleanup_pop ()
> was non-zero.
> .SS Program source
> \&
> .nf
> #include <pthread.h>
> #include <sys/types.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <unistd.h>
> #include <errno.h>
> 
> #define handle_error_en(en, msg) \\
>         do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
> 
> static int done = 0;
> static int cleanup_pop_arg = 0;
> static int cnt = 0;
> 
> static void
> cleanup_handler(void *arg)
> {
>     printf("Called clean\-up handler\\n");
>     cnt = 0;
> }
> 
> static void *
> thread_start(void *arg)
> {
>     time_t start, curr;
> 
>     printf("New thread started\\n");
> 
>     pthread_cleanup_push(cleanup_handler, NULL);
> 
>     curr = start = time(NULL);
> 
>     while (!done) {
>         pthread_testcancel();           /* A cancellation point */
>         if (curr < time(NULL)) {
>             curr = time(NULL);
>             printf("cnt = %d\\n", cnt);  /* A cancellation point */

printf() is not a mandatory CP (but is a CP on Linux).

>             cnt++;
>         }
>     }
> 
>     pthread_cleanup_pop(cleanup_pop_arg);
>     return NULL;
> }
> 
> int
> main(int argc, char *argv[])
> {
>     pthread_t thr;
>     int s;
>     void *res;
> 
>     s = pthread_create(&thr, NULL, thread_start, (void *) 1);

Why (void*) 1 as arg?

>     if (s != 0)
>         handle_error_en(s, "pthread_create");
> 
>     sleep(2);           /* Allow new thread to run a while */
> 
>     if (argc > 1) {
>         if (argc > 2)
>             cleanup_pop_arg = atoi(argv[2]);
>         done = 1;
> 
>     } else {
>         printf("Canceling thread\\n");
>         s = pthread_cancel(thr);
>         if (s != 0)
>             handle_error_en(s, "pthread_cancel");
>     }
> 
>     s = pthread_join(thr, &res);
>     if (s != 0)
>         handle_error_en(s, "pthread_join");
> 
>     if (res == PTHREAD_CANCELED)
>         printf("Thread was canceled; cnt = %d\\n", cnt);
>     else
>         printf("Thread terminated normally; cnt = %d\\n", cnt);
>     exit(EXIT_SUCCESS);
> }

I see a major deficiency in your code. Unless I am mistaken, the global 
variable <done> and <cleanup_pop_arg> are accessed from two different 
threads. Following the POSIX memory model, you need mutex to synchronize 
the visibility.

> .fi
> .SH SEE ALSO
> .BR pthread_cancel (3),
> .BR pthread_cleanup_push_defer_np (3),
> .BR pthread_setcancelstate (3),
> .BR pthread_testcancel (3),
> .BR pthreads (7)
> 

A last comment: pthread_join(3) and pthread_cond_wait(3) are CP, so it 
would be nice to describe the cancellation semantic in their respective 
man-page.

Besides that, you need clean-up handler if you use deferred cancellation 
on pthread_cond_wait(3). Indeed, when this function is cancelled, the 
mutex is relocked.So, you need clean-up handler to unlock the mutex.
--
To unsubscribe from this list: send the line "unsubscribe linux-man" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

  parent reply	other threads:[~2008-11-22  7:17 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-11-14 17:19 For review: pthread_cleanup_push.3 Michael Kerrisk
     [not found] ` <cfd18e0f0811140919g11e625a2i8546b3296d008dce-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2008-11-22  7:17   ` Loic Domaigne [this message]
     [not found]     ` <4927B203.3000702-Z4JMKDdsf89Wk0Htik3J/w@public.gmane.org>
2008-11-24 22:04       ` Michael Kerrisk
     [not found]         ` <cfd18e0f0811241404o1415d18bq497ff34b29502263-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2008-11-25 21:11           ` Loic Domaigne
     [not found]             ` <492C69E6.3030402-Z4JMKDdsf89Wk0Htik3J/w@public.gmane.org>
2008-11-30 20:10               ` Loic Domaigne

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4927B203.3000702@domaigne.com \
    --to=tech-z4jmkddsf89wk0htik3j/w@public.gmane.org \
    --cc=K.Weiss-Pt+Xe7GJXK+P2YhJcF5u+nqWYbMAw+HU@public.gmane.org \
    --cc=bert.wesarg-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org \
    --cc=josv-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org \
    --cc=linux-man-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox