Back to index

glibc  2.9
tst-cancel20.c
Go to the documentation of this file.
00001 /* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <errno.h>
00021 #include <pthread.h>
00022 #include <signal.h>
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <unistd.h>
00026 
00027 
00028 static int fd[4];
00029 static pthread_barrier_t b;
00030 volatile int in_sh_body;
00031 unsigned long cleanups;
00032 
00033 static void
00034 cl (void *arg)
00035 {
00036   cleanups = (cleanups << 4) | (long) arg;
00037 }
00038 
00039 
00040 static void __attribute__((noinline))
00041 sh_body (void)
00042 {
00043   char c;
00044 
00045   pthread_cleanup_push (cl, (void *) 1L);
00046 
00047   in_sh_body = 1;
00048   if (read (fd[2], &c, 1) == 1)
00049     {
00050       puts ("read succeeded");
00051       exit (1);
00052     }
00053 
00054   pthread_cleanup_pop (0);
00055 }
00056 
00057 
00058 static void
00059 sh (int sig)
00060 {
00061   pthread_cleanup_push (cl, (void *) 2L);
00062   sh_body ();
00063   in_sh_body = 0;
00064 
00065   pthread_cleanup_pop (0);
00066 }
00067 
00068 
00069 static void __attribute__((noinline))
00070 tf_body (void)
00071 {
00072   char c;
00073 
00074   pthread_cleanup_push (cl, (void *) 3L);
00075 
00076   int r = pthread_barrier_wait (&b);
00077   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
00078     {
00079       puts ("child thread: barrier_wait failed");
00080       exit (1);
00081     }
00082 
00083   if (read (fd[0], &c, 1) == 1)
00084     {
00085       puts ("read succeeded");
00086       exit (1);
00087     }
00088 
00089   read (fd[0], &c, 1);
00090 
00091   pthread_cleanup_pop (0);
00092 }
00093 
00094 
00095 static void *
00096 tf (void *arg)
00097 {
00098   pthread_cleanup_push (cl, (void *) 4L);
00099   tf_body ();
00100   pthread_cleanup_pop (0);
00101   return NULL;
00102 }
00103 
00104 
00105 static int
00106 do_one_test (void)
00107 {
00108   in_sh_body = 0;
00109   cleanups = 0;
00110   if (pipe (fd) != 0 || pipe (fd + 2) != 0)
00111     {
00112       puts ("pipe failed");
00113       return 1;
00114     }
00115 
00116   pthread_t th;
00117   if (pthread_create (&th, NULL, tf, NULL) != 0)
00118     {
00119       puts ("create failed");
00120       return 1;
00121     }
00122 
00123   int r = pthread_barrier_wait (&b);
00124   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
00125     {
00126       puts ("parent thread: barrier_wait failed");
00127       return 1;
00128     }
00129 
00130   sleep (1);
00131 
00132   r = pthread_kill (th, SIGHUP);
00133   if (r)
00134     {
00135       errno = r;
00136       printf ("pthread_kill failed %m\n");
00137       return 1;
00138     }
00139 
00140   while (in_sh_body == 0)
00141     sleep (1);
00142 
00143   if (pthread_cancel (th) != 0)
00144     {
00145       puts ("cancel failed");
00146       return 1;
00147     }
00148 
00149   /* This will cause the read in the child to return.  */
00150   close (fd[0]);
00151   close (fd[1]);
00152   close (fd[2]);
00153   close (fd[3]);
00154 
00155   void *ret;
00156   if (pthread_join (th, &ret) != 0)
00157     {
00158       puts ("join failed");
00159       return 1;
00160     }
00161 
00162   if (ret != PTHREAD_CANCELED)
00163     {
00164       puts ("result is wrong");
00165       return 1;
00166     }
00167 
00168   if (cleanups != 0x1234L)
00169     {
00170       printf ("called cleanups %lx\n", cleanups);
00171       return 1;
00172     }
00173 
00174   return 0;
00175 }
00176 
00177 
00178 static int
00179 do_test (void)
00180 {
00181   stack_t ss;
00182   ss.ss_sp = malloc (2 * SIGSTKSZ);
00183   if (ss.ss_sp == NULL)
00184     {
00185       puts ("failed to allocate alternate stack");
00186       return 1;
00187     }
00188   ss.ss_flags = 0;
00189   ss.ss_size = 2 * SIGSTKSZ;
00190   if (sigaltstack (&ss, NULL) < 0)
00191     {
00192       printf ("sigaltstack failed %m\n");
00193       return 1;
00194     }
00195 
00196   if (pthread_barrier_init (&b, NULL, 2) != 0)
00197     {
00198       puts ("barrier_init failed");
00199       return 1;
00200     }
00201 
00202   struct sigaction sa;
00203   sa.sa_handler = sh;
00204   sigemptyset (&sa.sa_mask);
00205   sa.sa_flags = 0;
00206 
00207   if (sigaction (SIGHUP, &sa, NULL) != 0)
00208     {
00209       puts ("sigaction failed");
00210       return 1;
00211     }
00212 
00213   puts ("sa_flags = 0 test");
00214   if (do_one_test ())
00215     return 1;
00216 
00217   sa.sa_handler = sh;
00218   sigemptyset (&sa.sa_mask);
00219   sa.sa_flags = SA_ONSTACK;
00220 
00221   if (sigaction (SIGHUP, &sa, NULL) != 0)
00222     {
00223       puts ("sigaction failed");
00224       return 1;
00225     }
00226 
00227   puts ("sa_flags = SA_ONSTACK test");
00228   if (do_one_test ())
00229     return 1;
00230 
00231   sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh;
00232   sigemptyset (&sa.sa_mask);
00233   sa.sa_flags = SA_SIGINFO;
00234 
00235   if (sigaction (SIGHUP, &sa, NULL) != 0)
00236     {
00237       puts ("sigaction failed");
00238       return 1;
00239     }
00240 
00241   puts ("sa_flags = SA_SIGINFO test");
00242   if (do_one_test ())
00243     return 1;
00244 
00245   sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh;
00246   sigemptyset (&sa.sa_mask);
00247   sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
00248 
00249   if (sigaction (SIGHUP, &sa, NULL) != 0)
00250     {
00251       puts ("sigaction failed");
00252       return 1;
00253     }
00254 
00255   puts ("sa_flags = SA_SIGINFO|SA_ONSTACK test");
00256   if (do_one_test ())
00257     return 1;
00258 
00259   return 0;
00260 }
00261 
00262 #define TIMEOUT 40
00263 #define TEST_FUNCTION do_test ()
00264 #include "../test-skeleton.c"