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
33static const char *command;
34static const char *pidfile;
35static const char *semfile;
36static char *pidfilename;
37static char *semfilename;
38
39static sem_t *sem;
40
41static void *
42tf (void *arg)
43{
44 char *cmd = xasprintf (format: "%s --direct --sem %s --pidfile %s",
45 command, semfilename, pidfilename);
46 system (command: cmd);
47 /* This call should never return. */
48 return NULL;
49}
50
51static void
52sl (void)
53{
54 FILE *f = xfopen (path: pidfile, mode: "w");
55
56 fprintf (f, "%lld\n", (long long) getpid ());
57 fflush (f);
58
59 if (sem_post (sem: 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 (fd: fileno (f), F_SETLK, &fl) != 0)
70 FAIL_EXIT1 ("fcntl (F_SETFL): %m");
71
72 sigset_t ss;
73 sigfillset (&ss);
74 sigsuspend (set: &ss);
75 exit (0);
76}
77
78
79static void
80do_prepare (int argc, char *argv[])
81{
82 int semfd;
83 if (semfile == NULL)
84 semfd = create_temp_file (base: "tst-cancel7.", filename: &semfilename);
85 else
86 semfd = open (file: semfile, O_RDWR);
87 TEST_VERIFY_EXIT (semfd != -1);
88
89 sem = xmmap (NULL, length: sizeof (sem_t), PROT_READ | PROT_WRITE, MAP_SHARED,
90 fd: semfd);
91 TEST_VERIFY_EXIT (sem != SEM_FAILED);
92 if (semfile == NULL)
93 {
94 xftruncate (fd: semfd, length: 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 (base: "tst-cancel7-pid-", filename: &pidfilename);
105 if (fd == -1)
106 FAIL_EXIT1 ("create_temp_file failed: %m");
107
108 xwrite (fd, " ", 1);
109 xclose (fd);
110}
111
112
113static int
114do_test (void)
115{
116 pthread_t th = xpthread_create (NULL, thread_func: tf, NULL);
117
118 /* Wait to cancel until after the pid is written. */
119 if (sem_wait (sem: sem) != 0)
120 FAIL_EXIT1 ("sem_wait: %m");
121
122 xpthread_cancel (thr: th);
123 void *r = xpthread_join (thr: th);
124
125 FILE *f = xfopen (path: pidfilename, mode: "r+");
126
127 long long ll;
128 if (fscanf (stream: f, format: "%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 (fd: fileno (f), F_GETLK, &fl) != 0)
139 FAIL_EXIT1 ("fcntl: %m");
140
141 if (fl.l_type != F_UNLCK)
142 {
143 printf (format: "child %lld still running\n", (long long) fl.l_pid);
144 if (fl.l_pid == ll)
145 kill (pid: fl.l_pid, SIGKILL);
146
147 return 1;
148 }
149
150 xfclose (f);
151
152 return r != PTHREAD_CANCELED;
153}
154
155static void
156do_cleanup (void)
157{
158 FILE *f = fopen (pidfilename, "r+");
159 long long ll;
160
161 if (f != NULL && fscanf (stream: f, format: "%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 (fd: fileno (f), F_GETLK, &fl) == 0 && fl.l_type != F_UNLCK
171 && fl.l_pid == ll)
172 kill (pid: 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 },
185static void
186cmdline_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

source code of glibc/nptl/tst-cancel7.c