(root)/
glibc-2.38/
sysdeps/
pthread/
tst-cancel29.c
       1  /* Check if a thread that disables cancellation and which call functions
       2     that might be interrupted by a signal do not see the internal SIGCANCEL.
       3  
       4     Copyright (C) 2022-2023 Free Software Foundation, Inc.
       5     This file is part of the GNU C Library.
       6  
       7     The GNU C Library is free software; you can redistribute it and/or
       8     modify it under the terms of the GNU Lesser General Public
       9     License as published by the Free Software Foundation; either
      10     version 2.1 of the License, or (at your option) any later version.
      11  
      12     The GNU C Library is distributed in the hope that it will be useful,
      13     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15     Lesser General Public License for more details.
      16  
      17     You should have received a copy of the GNU Lesser General Public
      18     License along with the GNU C Library; if not, see
      19     <https://www.gnu.org/licenses/>.  */
      20  
      21  #include <array_length.h>
      22  #include <errno.h>
      23  #include <inttypes.h>
      24  #include <poll.h>
      25  #include <support/check.h>
      26  #include <support/support.h>
      27  #include <support/temp_file.h>
      28  #include <support/xthread.h>
      29  #include <sys/socket.h>
      30  #include <signal.h>
      31  #include <stdio.h>
      32  #include <unistd.h>
      33  
      34  /* On Linux some interfaces are never restarted after being interrupted by
      35     a signal handler, regardless of the use of SA_RESTART.  It means that
      36     if asynchronous cancellation is not enabled, the pthread_cancel can not
      37     set the internal SIGCANCEL otherwise the interface might see a spurious
      38     EINTR failure.  */
      39  
      40  static pthread_barrier_t b;
      41  
      42  /* Cleanup handling test.  */
      43  static int cl_called;
      44  static void
      45  cl (void *arg)
      46  {
      47    ++cl_called;
      48  }
      49  
      50  static void *
      51  tf_sigtimedwait (void *arg)
      52  {
      53    pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
      54    xpthread_barrier_wait (&b);
      55  
      56    int r;
      57    pthread_cleanup_push (cl, NULL);
      58  
      59    sigset_t mask;
      60    sigemptyset (&mask);
      61    r = sigtimedwait (&mask, NULL, &(struct timespec) { 0, 250000000 });
      62    if (r != -1)
      63      return (void*) -1;
      64    if (errno != EAGAIN)
      65      return (void*) -2;
      66  
      67    pthread_cleanup_pop (0);
      68    return NULL;
      69  }
      70  
      71  static void *
      72  tf_poll (void *arg)
      73  {
      74    pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
      75    xpthread_barrier_wait (&b);
      76  
      77    int r;
      78    pthread_cleanup_push (cl, NULL);
      79  
      80    r = poll (NULL, 0, 250);
      81    if (r != 0)
      82      return (void*) -1;
      83  
      84    pthread_cleanup_pop (0);
      85    return NULL;
      86  }
      87  
      88  static void *
      89  tf_ppoll (void *arg)
      90  {
      91    pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
      92  
      93    xpthread_barrier_wait (&b);
      94  
      95    int r;
      96    pthread_cleanup_push (cl, NULL);
      97  
      98    r = ppoll (NULL, 0, &(struct timespec) { 0, 250000000 }, NULL);
      99    if (r != 0)
     100      return (void*) -1;
     101  
     102    pthread_cleanup_pop (0);
     103    return NULL;
     104  }
     105  
     106  static void *
     107  tf_select (void *arg)
     108  {
     109    pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
     110    xpthread_barrier_wait (&b);
     111  
     112    int r;
     113    pthread_cleanup_push (cl, NULL);
     114  
     115    r = select (0, NULL, NULL, NULL, &(struct timeval) { 0, 250000 });
     116    if (r != 0)
     117      return (void*) -1;
     118  
     119    pthread_cleanup_pop (0);
     120    return NULL;
     121  }
     122  
     123  static void *
     124  tf_pselect (void *arg)
     125  {
     126    pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
     127    xpthread_barrier_wait (&b);
     128  
     129    int r;
     130    pthread_cleanup_push (cl, NULL);
     131  
     132    r = pselect (0, NULL, NULL, NULL, &(struct timespec) { 0, 250000000 }, NULL);
     133    if (r != 0)
     134      return (void*) -1;
     135  
     136    pthread_cleanup_pop (0);
     137    return NULL;
     138  }
     139  
     140  static void *
     141  tf_clock_nanosleep (void *arg)
     142  {
     143    pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
     144    xpthread_barrier_wait (&b);
     145  
     146    int r;
     147    pthread_cleanup_push (cl, NULL);
     148  
     149    r = clock_nanosleep (CLOCK_REALTIME, 0, &(struct timespec) { 0, 250000000 },
     150  		       NULL);
     151    if (r != 0)
     152      return (void*) -1;
     153  
     154    pthread_cleanup_pop (0);
     155    return NULL;
     156  }
     157  
     158  struct cancel_test_t
     159  {
     160    const char *name;
     161    void * (*cf) (void *);
     162  } tests[] =
     163  {
     164    { "sigtimedwait",    tf_sigtimedwait,    },
     165    { "poll",            tf_poll,            },
     166    { "ppoll",           tf_ppoll,           },
     167    { "select",          tf_select,          },
     168    { "pselect",         tf_pselect  ,       },
     169    { "clock_nanosleep", tf_clock_nanosleep, },
     170  };
     171  
     172  static int
     173  do_test (void)
     174  {
     175    for (int i = 0; i < array_length (tests); i++)
     176      {
     177        xpthread_barrier_init (&b, NULL, 2);
     178  
     179        cl_called = 0;
     180  
     181        pthread_t th = xpthread_create (NULL, tests[i].cf, NULL);
     182  
     183        xpthread_barrier_wait (&b);
     184  
     185        struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 };
     186        while (nanosleep (&ts, &ts) != 0)
     187  	continue;
     188  
     189        xpthread_cancel (th);
     190  
     191        void *status = xpthread_join (th);
     192        if (status != NULL)
     193  	printf ("test '%s' failed: %" PRIdPTR "\n", tests[i].name,
     194  		(intptr_t) status);
     195        TEST_VERIFY (status == NULL);
     196  
     197        xpthread_barrier_destroy (&b);
     198  
     199        TEST_COMPARE (cl_called, 0);
     200  
     201        printf ("in-time cancel test of '%s' successful\n", tests[i].name);
     202      }
     203  
     204    return 0;
     205  }
     206  
     207  #include <support/test-driver.c>