Back to index

glibc  2.9
tst-cancel21.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 <sys/wait.h>
00026 #include <unistd.h>
00027 
00028 
00029 static int fd[4];
00030 static pthread_barrier_t b;
00031 volatile int in_sh_body;
00032 unsigned long cleanups;
00033 
00034 static void
00035 cl (void *arg)
00036 {
00037   cleanups = (cleanups << 4) | (long) arg;
00038 }
00039 
00040 
00041 static void __attribute__((noinline))
00042 sh_body (void)
00043 {
00044   char c;
00045 
00046   pthread_cleanup_push (cl, (void *) 1L);
00047 
00048   in_sh_body = 1;
00049   if (read (fd[2], &c, 1) == 1)
00050     {
00051       puts ("read succeeded");
00052       exit (1);
00053     }
00054 
00055   pthread_cleanup_pop (0);
00056 }
00057 
00058 
00059 static void
00060 sh (int sig)
00061 {
00062   pthread_cleanup_push (cl, (void *) 2L);
00063   sh_body ();
00064   in_sh_body = 0;
00065 
00066   pthread_cleanup_pop (0);
00067 }
00068 
00069 
00070 static void __attribute__((noinline))
00071 tf_body (void)
00072 {
00073   char c;
00074 
00075   pthread_cleanup_push (cl, (void *) 3L);
00076 
00077   int r = pthread_barrier_wait (&b);
00078   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
00079     {
00080       puts ("child thread: barrier_wait failed");
00081       exit (1);
00082     }
00083 
00084   if (read (fd[0], &c, 1) == 1)
00085     {
00086       puts ("read succeeded");
00087       exit (1);
00088     }
00089 
00090   read (fd[0], &c, 1);
00091 
00092   pthread_cleanup_pop (0);
00093 }
00094 
00095 
00096 static void *
00097 tf (void *arg)
00098 {
00099   pthread_t th = (pthread_t) arg;
00100 
00101   int r = pthread_barrier_wait (&b);
00102   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
00103     {
00104       puts ("parent thread: barrier_wait failed");
00105       exit (1);
00106     }
00107 
00108   sleep (1);
00109 
00110   r = pthread_kill (th, SIGHUP);
00111   if (r)
00112     {
00113       errno = r;
00114       printf ("pthread_kill failed %m\n");
00115       exit (1);
00116     }
00117 
00118   while (in_sh_body == 0)
00119     sleep (1);
00120 
00121   if (pthread_cancel (th) != 0)
00122     {
00123       puts ("cancel failed");
00124       exit (1);
00125     }
00126 
00127   /* This will cause the read in the initial thread to return.  */
00128   close (fd[0]);
00129   close (fd[1]);
00130   close (fd[2]);
00131   close (fd[3]);
00132 
00133   void *ret;
00134   if (pthread_join (th, &ret) != 0)
00135     {
00136       puts ("join failed");
00137       exit (1);
00138     }
00139 
00140   if (ret != PTHREAD_CANCELED)
00141     {
00142       puts ("result is wrong");
00143       exit (1);
00144     }
00145 
00146   if (cleanups != 0x1234L)
00147     {
00148       printf ("called cleanups %lx\n", cleanups);
00149       exit (1);
00150     }
00151 
00152   if (pthread_barrier_destroy (&b))
00153     {
00154       puts ("barrier destroy failed");
00155       exit (1);
00156     }
00157 
00158   exit (0);
00159 }
00160 
00161 
00162 static int
00163 do_one_test (void)
00164 {
00165   in_sh_body = 0;
00166 
00167   pid_t pid = fork ();
00168 
00169   if (pid == -1)
00170     {
00171       printf ("fork failed: %m\n");
00172       return 1;
00173     }
00174 
00175   if (pid)
00176     {
00177       int status;
00178       if (waitpid (pid, &status, 0) < 0)
00179        {
00180          printf ("waitpid failed %m\n");
00181          return 1;
00182        }
00183 
00184       return !WIFEXITED (status) || WEXITSTATUS (status);
00185     }
00186 
00187   if (pthread_barrier_init (&b, NULL, 2) != 0)
00188     {
00189       puts ("barrier_init failed");
00190       exit (1);
00191     }
00192 
00193   cleanups = 0;
00194   if (pipe (fd) != 0 || pipe (fd + 2) != 0)
00195     {
00196       puts ("pipe failed");
00197       exit (1);
00198     }
00199 
00200   pthread_t th;
00201   if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0)
00202     {
00203       puts ("create failed");
00204       exit (1);
00205     }
00206 
00207   pthread_cleanup_push (cl, (void *) 4L);
00208   tf_body ();
00209   pthread_cleanup_pop (0);
00210   exit (1);
00211 }
00212 
00213 
00214 static int
00215 do_test (void)
00216 {
00217   stack_t ss;
00218   ss.ss_sp = malloc (2 * SIGSTKSZ);
00219   if (ss.ss_sp == NULL)
00220     {
00221       puts ("failed to allocate alternate stack");
00222       return 1;
00223     }
00224   ss.ss_flags = 0;
00225   ss.ss_size = 2 * SIGSTKSZ;
00226   if (sigaltstack (&ss, NULL) < 0)
00227     {
00228       printf ("sigaltstack failed %m\n");
00229       return 1;
00230     }
00231 
00232   struct sigaction sa;
00233   sa.sa_handler = sh;
00234   sigemptyset (&sa.sa_mask);
00235   sa.sa_flags = 0;
00236 
00237   if (sigaction (SIGHUP, &sa, NULL) != 0)
00238     {
00239       puts ("sigaction failed");
00240       return 1;
00241     }
00242 
00243   puts ("sa_flags = 0 test");
00244   if (do_one_test ())
00245     return 1;
00246 
00247   sa.sa_handler = sh;
00248   sigemptyset (&sa.sa_mask);
00249   sa.sa_flags = SA_ONSTACK;
00250 
00251   if (sigaction (SIGHUP, &sa, NULL) != 0)
00252     {
00253       puts ("sigaction failed");
00254       return 1;
00255     }
00256 
00257   puts ("sa_flags = SA_ONSTACK test");
00258   if (do_one_test ())
00259     return 1;
00260 
00261   sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh;
00262   sigemptyset (&sa.sa_mask);
00263   sa.sa_flags = SA_SIGINFO;
00264 
00265   if (sigaction (SIGHUP, &sa, NULL) != 0)
00266     {
00267       puts ("sigaction failed");
00268       return 1;
00269     }
00270 
00271   puts ("sa_flags = SA_SIGINFO test");
00272   if (do_one_test ())
00273     return 1;
00274 
00275   sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh;
00276   sigemptyset (&sa.sa_mask);
00277   sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
00278 
00279   if (sigaction (SIGHUP, &sa, NULL) != 0)
00280     {
00281       puts ("sigaction failed");
00282       return 1;
00283     }
00284 
00285   puts ("sa_flags = SA_SIGINFO|SA_ONSTACK test");
00286   if (do_one_test ())
00287     return 1;
00288 
00289   return 0;
00290 }
00291 
00292 #define TIMEOUT 40
00293 #define TEST_FUNCTION do_test ()
00294 #include "../test-skeleton.c"