1 /* Copyright (C) 2002-2022 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 *
tf(void * arg)42 tf (void *arg)
43 {
44 char *cmd = xasprintf ("%s --direct --sem %s --pidfile %s",
45 command, semfilename, pidfilename);
46 system (cmd);
47 /* This call should never return. */
48 return NULL;
49 }
50
51 static void
sl(void)52 sl (void)
53 {
54 FILE *f = xfopen (pidfile, "w");
55
56 fprintf (f, "%lld\n", (long long) getpid ());
57 fflush (f);
58
59 if (sem_post (sem) != 0)
60 FAIL_EXIT1 ("sem_post: %m");
61
62 struct flock fl =
63 {
64 .l_type = F_WRLCK,
65 .l_start = 0,
66 .l_whence = SEEK_SET,
67 .l_len = 1
68 };
69 if (fcntl (fileno (f), F_SETLK, &fl) != 0)
70 FAIL_EXIT1 ("fcntl (F_SETFL): %m");
71
72 sigset_t ss;
73 sigfillset (&ss);
74 sigsuspend (&ss);
75 exit (0);
76 }
77
78
79 static void
do_prepare(int argc,char * argv[])80 do_prepare (int argc, char *argv[])
81 {
82 int semfd;
83 if (semfile == NULL)
84 semfd = create_temp_file ("tst-cancel7.", &semfilename);
85 else
86 semfd = open (semfile, O_RDWR);
87 TEST_VERIFY_EXIT (semfd != -1);
88
89 sem = xmmap (NULL, sizeof (sem_t), PROT_READ | PROT_WRITE, MAP_SHARED,
90 semfd);
91 TEST_VERIFY_EXIT (sem != SEM_FAILED);
92 if (semfile == NULL)
93 {
94 xftruncate (semfd, sizeof (sem_t));
95 TEST_VERIFY_EXIT (sem_init (sem, 1, 0) != -1);
96 }
97
98 if (command == NULL)
99 command = argv[0];
100
101 if (pidfile)
102 sl ();
103
104 int fd = create_temp_file ("tst-cancel7-pid-", &pidfilename);
105 if (fd == -1)
106 FAIL_EXIT1 ("create_temp_file failed: %m");
107
108 xwrite (fd, " ", 1);
109 xclose (fd);
110 }
111
112
113 static int
do_test(void)114 do_test (void)
115 {
116 pthread_t th = xpthread_create (NULL, tf, NULL);
117
118 /* Wait to cancel until after the pid is written. */
119 if (sem_wait (sem) != 0)
120 FAIL_EXIT1 ("sem_wait: %m");
121
122 xpthread_cancel (th);
123 void *r = xpthread_join (th);
124
125 FILE *f = xfopen (pidfilename, "r+");
126
127 long long ll;
128 if (fscanf (f, "%lld\n", &ll) != 1)
129 FAIL_EXIT1 ("fscanf: %m");
130
131 struct flock fl =
132 {
133 .l_type = F_WRLCK,
134 .l_start = 0,
135 .l_whence = SEEK_SET,
136 .l_len = 1
137 };
138 if (fcntl (fileno (f), F_GETLK, &fl) != 0)
139 FAIL_EXIT1 ("fcntl: %m");
140
141 if (fl.l_type != F_UNLCK)
142 {
143 printf ("child %lld still running\n", (long long) fl.l_pid);
144 if (fl.l_pid == ll)
145 kill (fl.l_pid, SIGKILL);
146
147 return 1;
148 }
149
150 xfclose (f);
151
152 return r != PTHREAD_CANCELED;
153 }
154
155 static void
do_cleanup(void)156 do_cleanup (void)
157 {
158 FILE *f = fopen (pidfilename, "r+");
159 long long ll;
160
161 if (f != NULL && fscanf (f, "%lld\n", &ll) == 1)
162 {
163 struct flock fl =
164 {
165 .l_type = F_WRLCK,
166 .l_start = 0,
167 .l_whence = SEEK_SET,
168 .l_len = 1
169 };
170 if (fcntl (fileno (f), F_GETLK, &fl) == 0 && fl.l_type != F_UNLCK
171 && fl.l_pid == ll)
172 kill (fl.l_pid, SIGKILL);
173
174 fclose (f);
175 }
176 }
177
178 #define OPT_COMMAND 10000
179 #define OPT_PIDFILE 10001
180 #define OPT_SEMFILE 10002
181 #define CMDLINE_OPTIONS \
182 { "command", required_argument, NULL, OPT_COMMAND }, \
183 { "pidfile", required_argument, NULL, OPT_PIDFILE }, \
184 { "sem", required_argument, NULL, OPT_SEMFILE },
185 static void
cmdline_process(int c)186 cmdline_process (int c)
187 {
188 switch (c)
189 {
190 case OPT_COMMAND:
191 command = optarg;
192 break;
193 case OPT_PIDFILE:
194 pidfile = optarg;
195 break;
196 case OPT_SEMFILE:
197 semfile = optarg;
198 break;
199 }
200 }
201 #define CMDLINE_PROCESS cmdline_process
202 #define CLEANUP_HANDLER do_cleanup
203 #define PREPARE do_prepare
204 #include <support/test-driver.c>
205