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

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