(root)/
glibc-2.38/
nptl/
tst-cancel7.c
       1  /* Copyright (C) 2002-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <errno.h>
      19  #include <fcntl.h>
      20  #include <getopt.h>
      21  #include <signal.h>
      22  #include <stdlib.h>
      23  #include <semaphore.h>
      24  #include <sys/mman.h>
      25  
      26  #include <support/check.h>
      27  #include <support/support.h>
      28  #include <support/temp_file.h>
      29  #include <support/xstdio.h>
      30  #include <support/xunistd.h>
      31  #include <support/xthread.h>
      32  
      33  static const char *command;
      34  static const char *pidfile;
      35  static const char *semfile;
      36  static char *pidfilename;
      37  static char *semfilename;
      38  
      39  static sem_t *sem;
      40  
      41  static void *
      42  tf (void *arg)
      43  {
      44    char *cmd = xasprintf ("%s --direct --sem %s --pidfile %s",
      45  			 command, semfilename, pidfilename);
      46    if (system (cmd))
      47      FAIL_EXIT1("system call unexpectedly returned");
      48    /* This call should never return.  */
      49    return NULL;
      50  }
      51  
      52  static void
      53  sl (void)
      54  {
      55    FILE *f = xfopen (pidfile, "w");
      56  
      57    fprintf (f, "%lld\n", (long long) getpid ());
      58    fflush (f);
      59  
      60    if (sem_post (sem) != 0)
      61      FAIL_EXIT1 ("sem_post: %m");
      62  
      63    struct flock fl =
      64      {
      65        .l_type = F_WRLCK,
      66        .l_start = 0,
      67        .l_whence = SEEK_SET,
      68        .l_len = 1
      69      };
      70    if (fcntl (fileno (f), F_SETLK, &fl) != 0)
      71      FAIL_EXIT1 ("fcntl (F_SETFL): %m");
      72  
      73    sigset_t ss;
      74    sigfillset (&ss);
      75    sigsuspend (&ss);
      76    exit (0);
      77  }
      78  
      79  
      80  static void
      81  do_prepare (int argc, char *argv[])
      82  {
      83    int semfd;
      84    if (semfile == NULL)
      85      semfd = create_temp_file ("tst-cancel7.", &semfilename);
      86    else
      87      semfd = open (semfile, O_RDWR);
      88    TEST_VERIFY_EXIT (semfd != -1);
      89  
      90    sem = xmmap (NULL, sizeof (sem_t), PROT_READ | PROT_WRITE, MAP_SHARED,
      91  	       semfd);
      92    TEST_VERIFY_EXIT (sem != SEM_FAILED);
      93    if (semfile == NULL)
      94      {
      95        xftruncate (semfd, sizeof (sem_t));
      96        TEST_VERIFY_EXIT (sem_init (sem, 1, 0) != -1);
      97      }
      98  
      99    if (command == NULL)
     100      command = argv[0];
     101  
     102    if (pidfile)
     103      sl ();
     104  
     105    int fd = create_temp_file ("tst-cancel7-pid-", &pidfilename);
     106    if (fd == -1)
     107      FAIL_EXIT1 ("create_temp_file failed: %m");
     108  
     109    xwrite (fd, " ", 1);
     110    xclose (fd);
     111  }
     112  
     113  
     114  static int
     115  do_test (void)
     116  {
     117    pthread_t th = xpthread_create (NULL, tf, NULL);
     118  
     119    /* Wait to cancel until after the pid is written.  */
     120    if (sem_wait (sem) != 0)
     121      FAIL_EXIT1 ("sem_wait: %m");
     122  
     123    xpthread_cancel (th);
     124    void *r = xpthread_join (th);
     125  
     126    FILE *f = xfopen (pidfilename, "r+");
     127  
     128    long long ll;
     129    if (fscanf (f, "%lld\n", &ll) != 1)
     130      FAIL_EXIT1 ("fscanf: %m");
     131  
     132    struct flock fl =
     133      {
     134        .l_type = F_WRLCK,
     135        .l_start = 0,
     136        .l_whence = SEEK_SET,
     137        .l_len = 1
     138      };
     139    if (fcntl (fileno (f), F_GETLK, &fl) != 0)
     140      FAIL_EXIT1 ("fcntl: %m");
     141  
     142    if (fl.l_type != F_UNLCK)
     143      {
     144        printf ("child %lld still running\n", (long long) fl.l_pid);
     145        if (fl.l_pid == ll)
     146  	kill (fl.l_pid, SIGKILL);
     147  
     148        return 1;
     149      }
     150  
     151    xfclose (f);
     152  
     153    return r != PTHREAD_CANCELED;
     154  }
     155  
     156  static void
     157  do_cleanup (void)
     158  {
     159    FILE *f = fopen (pidfilename, "r+");
     160    long long ll;
     161  
     162    if (f != NULL && fscanf (f, "%lld\n", &ll) == 1)
     163      {
     164        struct flock fl =
     165  	{
     166  	  .l_type = F_WRLCK,
     167  	  .l_start = 0,
     168  	  .l_whence = SEEK_SET,
     169  	  .l_len = 1
     170  	};
     171        if (fcntl (fileno (f), F_GETLK, &fl) == 0 && fl.l_type != F_UNLCK
     172  	  && fl.l_pid == ll)
     173  	kill (fl.l_pid, SIGKILL);
     174  
     175        fclose (f);
     176      }
     177  }
     178  
     179  #define OPT_COMMAND	10000
     180  #define OPT_PIDFILE	10001
     181  #define OPT_SEMFILE	10002
     182  #define CMDLINE_OPTIONS \
     183    { "command", required_argument, NULL, OPT_COMMAND },	\
     184    { "pidfile", required_argument, NULL, OPT_PIDFILE },  \
     185    { "sem",     required_argument, NULL, OPT_SEMFILE },
     186  static void
     187  cmdline_process (int c)
     188  {
     189    switch (c)
     190      {
     191      case OPT_COMMAND:
     192        command = optarg;
     193        break;
     194      case OPT_PIDFILE:
     195        pidfile = optarg;
     196        break;
     197      case OPT_SEMFILE:
     198        semfile = optarg;
     199        break;
     200      }
     201  }
     202  #define CMDLINE_PROCESS cmdline_process
     203  #define CLEANUP_HANDLER do_cleanup
     204  #define PREPARE do_prepare
     205  #include <support/test-driver.c>