# pthread_cleanup_push

## NAME



           pthread_cleanup_push, pthread_cleanup_pop - push and pop thread
           cancelation clean-up handlers
    


## LIBRARY



           POSIX threads library (_libpthread_ , _-lpthread_)
    


## SYNOPSIS



           **#include <pthread.h>**
    
           **void pthread_cleanup_push(typeof(void (void *)) ***_routine_**, void ***_arg_**);**
           **void pthread_cleanup_pop(int** _execute_**);**
    


## DESCRIPTION



           These functions manipulate the calling thread's stack of thread-
           cancelation 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 **pthread_cleanup_push**() function pushes _routine_ onto the top of
           the stack of clean-up handlers.  When _routine_ is later invoked, it
           will be given _arg_ as its argument.
    
           The **pthread_cleanup_pop**() function removes the routine at the top
           of the stack of clean-up handlers, and optionally executes it if
           _execute_ is nonzero.
    
           A cancelation clean-up handler is popped from the stack and
           executed in the following circumstances:
    
           •  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.
    
           •  When a thread terminates by calling pthread_exit(3), all clean-
              up handlers are executed as described in the preceding point.
              (Clean-up handlers are _not_ called if the thread terminates by
              performing a _return_ from the thread start function.)
    
           •  When a thread calls **pthread_cleanup_pop**() with a nonzero
              _execute_ argument, the top-most clean-up handler is popped and
              executed.
    
           POSIX.1 permits **pthread_cleanup_push**() and **pthread_cleanup_pop**()
           to be implemented as macros that expand to text containing '**{** ' and
           '**}** ', 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.)
    
           Calling longjmp(3) (siglongjmp(3)) produces undefined results if
           any call has been made to **pthread_cleanup_push**() or
           **pthread_cleanup_pop**() without the matching call of the pair since
           the jump buffer was filled by setjmp(3) (sigsetjmp(3)).  Likewise,
           calling longjmp(3) (siglongjmp(3)) from inside a clean-up handler
           produces undefined results unless the jump buffer was also filled
           by setjmp(3) (sigsetjmp(3)) inside the handler.
    


## RETURN VALUE



           These functions do not return a value.
    


## ERRORS



           There are no errors.
    


## ATTRIBUTES



           For an explanation of the terms used in this section, see
           attributes(7).
           ┌──────────────────────────────────────┬───────────────┬─────────┐
           │ **Interface** │ **Attribute** │ **Value** │
           ├──────────────────────────────────────┼───────────────┼─────────┤
           │ **pthread_cleanup_push**(),              │ Thread safety │ MT-Safe │
           │ **pthread_cleanup_pop**()                │               │         │
           └──────────────────────────────────────┴───────────────┴─────────┘
    


## VERSIONS



           On glibc, the **pthread_cleanup_push**() and **pthread_cleanup_pop**()
           functions _are_ implemented as macros that expand to text containing
           '**{** ' and '**}** ', respectively.  This means that variables declared
           within the scope of paired calls to these functions will be
           visible within only that scope.
    
           POSIX.1 says that the effect of using _return_ , _break_ , _continue_ , or
           _goto_ to prematurely leave a block bracketed **pthread_cleanup_push**()
           and **pthread_cleanup_pop**() is undefined.  Portable applications
           should avoid doing this.
    


## STANDARDS



           POSIX.1-2008.
    


## EXAMPLES



           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 **pthread_cleanup_push**() and
           **pthread_cleanup_pop**().  This loop increments a global variable,
           _cnt_ , once each second.  Depending on what command-line arguments
           are supplied, the main thread sends the other thread a cancelation
           request, or sets a global variable that causes the other thread to
           exit its loop and terminate normally (by doing a _return_).
    
           In the following shell session, the main thread sends a
           cancelation request to the other thread:
    
               $ **./a.out** ;
               New thread started
               cnt = 0
               cnt = 1
               Canceling thread
               Called clean-up handler
               Thread was canceled; cnt = 0
    
           From the above, we see that the thread was canceled, and that the
           cancelation clean-up handler was called and it reset the value of
           the global variable _cnt_ to 0.
    
           In the next run, the main program sets a global variable that
           causes other thread to terminate normally:
    
               $ **./a.out x** ;
               New thread started
               cnt = 0
               cnt = 1
               Thread terminated normally; cnt = 2
    
           From the above, we see that the clean-up handler was not executed
           (because _cleanup_pop_arg_ was 0), and therefore the value of _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
           nonzero value for _cleanup_pop_arg_ :
    
               $ **./a.out x 1** ;
               New thread started
               cnt = 0
               cnt = 1
               Called clean-up handler
               Thread terminated normally; cnt = 0
    
           In the above, we see that although the thread was not canceled,
           the clean-up handler was executed, because the argument given to
           **pthread_cleanup_pop**() was nonzero.
    
       **Program source**
    
           #include <errno.h>
           #include <pthread.h>
           #include <stdio.h>
           #include <stdlib.h>
           #include <sys/types.h>
           #include <unistd.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 curr;
    
               printf("New thread started\n");
    
               pthread_cleanup_push(cleanup_handler, NULL);
    
               curr = time(NULL);
    
               while (!done) {
                   pthread_testcancel();           /* A cancelation point */
                   if (curr < time(NULL)) {
                       curr = time(NULL);
                       printf("cnt = %d\n", cnt);  /* A cancelation point */
                       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, NULL);
               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);
           }
    


* * *