Back to index

glibc  2.9
tst-cancel17.c
Go to the documentation of this file.
00001 /* Copyright (C) 2003, 2005 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Ulrich Drepper <drepper@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 <aio.h>
00021 #include <errno.h>
00022 #include <pthread.h>
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <unistd.h>
00027 
00028 
00029 static pthread_barrier_t b;
00030 
00031 
00032 /* Cleanup handling test.  */
00033 static int cl_called;
00034 
00035 static void
00036 cl (void *arg)
00037 {
00038   ++cl_called;
00039 }
00040 
00041 
00042 static void *
00043 tf (void *arg)
00044 {
00045   int r = pthread_barrier_wait (&b);
00046   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
00047     {
00048       puts ("tf: barrier_wait failed");
00049       exit (1);
00050     }
00051 
00052   pthread_cleanup_push (cl, NULL);
00053 
00054   const struct aiocb *l[1] = { arg };
00055 
00056   TEMP_FAILURE_RETRY (aio_suspend (l, 1, NULL));
00057 
00058   pthread_cleanup_pop (0);
00059 
00060   puts ("tf: aio_suspend returned");
00061 
00062   exit (1);
00063 }
00064 
00065 
00066 static void *
00067 tf2 (void *arg)
00068 {
00069   int r = pthread_barrier_wait (&b);
00070   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
00071     {
00072       puts ("tf2: barrier_wait failed");
00073       exit (1);
00074     }
00075 
00076   pthread_cleanup_push (cl, NULL);
00077 
00078   const struct aiocb *l[1] = { arg };
00079   struct timespec ts = { .tv_sec = 1000, .tv_nsec = 0 };
00080 
00081   TEMP_FAILURE_RETRY (aio_suspend (l, 1, &ts));
00082 
00083   pthread_cleanup_pop (0);
00084 
00085   puts ("tf2: aio_suspend returned");
00086 
00087   exit (1);
00088 }
00089 
00090 
00091 static int
00092 do_test (void)
00093 {
00094   int fds[2];
00095   if (pipe (fds) != 0)
00096     {
00097       puts ("pipe failed");
00098       return 1;
00099     }
00100 
00101   struct aiocb a, a2, *ap;
00102   char mem[1];
00103   memset (&a, '\0', sizeof (a));
00104   a.aio_fildes = fds[0];
00105   a.aio_buf = mem;
00106   a.aio_nbytes = sizeof (mem);
00107   if (aio_read (&a) != 0)
00108     {
00109       puts ("aio_read failed");
00110       return 1;
00111     }
00112 
00113   if (pthread_barrier_init (&b, NULL, 2) != 0)
00114     {
00115       puts ("barrier_init failed");
00116       return 1;
00117     }
00118 
00119   pthread_t th;
00120   if (pthread_create (&th, NULL, tf, &a) != 0)
00121     {
00122       puts ("1st create failed");
00123       return 1;
00124     }
00125 
00126   int r = pthread_barrier_wait (&b);
00127   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
00128     {
00129       puts ("barrier_wait failed");
00130       exit (1);
00131     }
00132 
00133   struct timespec  ts = { .tv_sec = 0, .tv_nsec = 100000000 };
00134   while (nanosleep (&ts, &ts) != 0)
00135     continue;
00136 
00137   puts ("going to cancel tf in-time");
00138   if (pthread_cancel (th) != 0)
00139     {
00140       puts ("1st cancel failed");
00141       return 1;
00142     }
00143 
00144   void *status;
00145   if (pthread_join (th, &status) != 0)
00146     {
00147       puts ("1st join failed");
00148       return 1;
00149     }
00150   if (status != PTHREAD_CANCELED)
00151     {
00152       puts ("1st thread not canceled");
00153       return 1;
00154     }
00155 
00156   if (cl_called == 0)
00157     {
00158       puts ("tf cleanup handler not called");
00159       return 1;
00160     }
00161   if (cl_called > 1)
00162     {
00163       puts ("tf cleanup handler called more than once");
00164       return 1;
00165     }
00166 
00167   cl_called = 0;
00168 
00169   if (pthread_create (&th, NULL, tf2, &a) != 0)
00170     {
00171       puts ("2nd create failed");
00172       return 1;
00173     }
00174 
00175   r = pthread_barrier_wait (&b);
00176   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
00177     {
00178       puts ("2nd barrier_wait failed");
00179       exit (1);
00180     }
00181 
00182   ts.tv_sec = 0;
00183   ts.tv_nsec = 100000000;
00184   while (nanosleep (&ts, &ts) != 0)
00185     continue;
00186 
00187   puts ("going to cancel tf2 in-time");
00188   if (pthread_cancel (th) != 0)
00189     {
00190       puts ("2nd cancel failed");
00191       return 1;
00192     }
00193 
00194   if (pthread_join (th, &status) != 0)
00195     {
00196       puts ("2nd join failed");
00197       return 1;
00198     }
00199   if (status != PTHREAD_CANCELED)
00200     {
00201       puts ("2nd thread not canceled");
00202       return 1;
00203     }
00204 
00205   if (cl_called == 0)
00206     {
00207       puts ("tf2 cleanup handler not called");
00208       return 1;
00209     }
00210   if (cl_called > 1)
00211     {
00212       puts ("tf2 cleanup handler called more than once");
00213       return 1;
00214     }
00215 
00216   puts ("in-time cancellation succeeded");
00217 
00218   ap = &a;
00219   if (aio_cancel (fds[0], &a) != AIO_CANCELED)
00220     {
00221       puts ("aio_cancel failed");
00222       /* If aio_cancel failed, we cannot reuse aiocb a.  */
00223       ap = &a2;
00224     }
00225 
00226 
00227   cl_called = 0;
00228 
00229   size_t len2 = fpathconf (fds[1], _PC_PIPE_BUF);
00230   size_t page_size = sysconf (_SC_PAGESIZE);
00231   len2 = 20 * (len2 < page_size ? page_size : len2) + sizeof (mem) + 1;
00232   char *mem2 = malloc (len2);
00233   if (mem2 == NULL)
00234     {
00235       puts ("could not allocate memory for pipe write");
00236       return 1;
00237     }
00238 
00239   memset (ap, '\0', sizeof (*ap));
00240   ap->aio_fildes = fds[1];
00241   ap->aio_buf = mem2;
00242   ap->aio_nbytes = len2;
00243   if (aio_write (ap) != 0)
00244     {
00245       puts ("aio_write failed");
00246       return 1;
00247     }
00248 
00249   if (pthread_create (&th, NULL, tf, ap) != 0)
00250     {
00251       puts ("3rd create failed");
00252       return 1;
00253     }
00254 
00255   puts ("going to cancel tf early");
00256   if (pthread_cancel (th) != 0)
00257     {
00258       puts ("3rd cancel failed");
00259       return 1;
00260     }
00261 
00262   r = pthread_barrier_wait (&b);
00263   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
00264     {
00265       puts ("3rd barrier_wait failed");
00266       exit (1);
00267     }
00268 
00269   if (pthread_join (th, &status) != 0)
00270     {
00271       puts ("3rd join failed");
00272       return 1;
00273     }
00274   if (status != PTHREAD_CANCELED)
00275     {
00276       puts ("3rd thread not canceled");
00277       return 1;
00278     }
00279 
00280   if (cl_called == 0)
00281     {
00282       puts ("tf cleanup handler not called");
00283       return 1;
00284     }
00285   if (cl_called > 1)
00286     {
00287       puts ("tf cleanup handler called more than once");
00288       return 1;
00289     }
00290 
00291   cl_called = 0;
00292 
00293   if (pthread_create (&th, NULL, tf2, ap) != 0)
00294     {
00295       puts ("4th create failed");
00296       return 1;
00297     }
00298 
00299   puts ("going to cancel tf2 early");
00300   if (pthread_cancel (th) != 0)
00301     {
00302       puts ("4th cancel failed");
00303       return 1;
00304     }
00305 
00306   r = pthread_barrier_wait (&b);
00307   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
00308     {
00309       puts ("4th barrier_wait failed");
00310       exit (1);
00311     }
00312 
00313   if (pthread_join (th, &status) != 0)
00314     {
00315       puts ("4th join failed");
00316       return 1;
00317     }
00318   if (status != PTHREAD_CANCELED)
00319     {
00320       puts ("4th thread not canceled");
00321       return 1;
00322     }
00323 
00324   if (cl_called == 0)
00325     {
00326       puts ("tf2 cleanup handler not called");
00327       return 1;
00328     }
00329   if (cl_called > 1)
00330     {
00331       puts ("tf2 cleanup handler called more than once");
00332       return 1;
00333     }
00334 
00335   puts ("early cancellation succeeded");
00336 
00337   return 0;
00338 }
00339 
00340 #define TEST_FUNCTION do_test ()
00341 #include "../test-skeleton.c"