xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/tgkill/tgkill03.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2018 Google, Inc.
4  *
5  * Test simple tgkill() error cases.
6  */
7 
8 #include <pthread.h>
9 #include <pwd.h>
10 #include <stdio.h>
11 #include <sys/types.h>
12 
13 #include "tst_safe_pthread.h"
14 #include "tst_test.h"
15 #include "tgkill.h"
16 
17 #define CHECK_ENOENT(x) ((x) == -1 && errno == ENOENT)
18 
19 static pthread_t child_thread;
20 
21 static pid_t parent_tgid;
22 static pid_t parent_tid;
23 static pid_t child_tid;
24 static pid_t defunct_tid;
25 
26 static const int invalid_pid = -1;
27 
child_thread_func(void * arg)28 static void *child_thread_func(void *arg)
29 {
30 	child_tid = sys_gettid();
31 
32 	TST_CHECKPOINT_WAKE_AND_WAIT(0);
33 
34 	return arg;
35 }
36 
defunct_thread_func(void * arg)37 static void *defunct_thread_func(void *arg)
38 {
39 	defunct_tid = sys_gettid();
40 
41 	return arg;
42 }
43 
setup(void)44 static void setup(void)
45 {
46 	sigset_t sigusr1;
47 	pthread_t defunct_thread;
48 	char defunct_tid_path[PATH_MAX];
49 	int ret;
50 
51 	sigemptyset(&sigusr1);
52 	sigaddset(&sigusr1, SIGUSR1);
53 	pthread_sigmask(SIG_BLOCK, &sigusr1, NULL);
54 
55 	parent_tgid = getpid();
56 	parent_tid = sys_gettid();
57 
58 	SAFE_PTHREAD_CREATE(&child_thread, NULL, child_thread_func, NULL);
59 
60 	TST_CHECKPOINT_WAIT(0);
61 
62 	SAFE_PTHREAD_CREATE(&defunct_thread, NULL, defunct_thread_func, NULL);
63 	SAFE_PTHREAD_JOIN(defunct_thread, NULL);
64 	sprintf(defunct_tid_path, "/proc/%d/task/%d", getpid(), defunct_tid);
65 	ret = TST_RETRY_FN_EXP_BACKOFF(access(defunct_tid_path, R_OK),
66 		CHECK_ENOENT, 15);
67 	if (!CHECK_ENOENT(ret))
68 		tst_brk(TBROK, "Timeout, %s still exists", defunct_tid_path);
69 }
70 
cleanup(void)71 static void cleanup(void)
72 {
73 	TST_CHECKPOINT_WAKE(0);
74 
75 	SAFE_PTHREAD_JOIN(child_thread, NULL);
76 }
77 
78 static const struct testcase {
79 	const char *desc;
80 	const int *tgid;
81 	const int *tid;
82 	const int sig;
83 	const int err;
84 } testcases[] = {
85 	{ "Invalid tgid", &invalid_pid, &parent_tid, SIGUSR1, EINVAL },
86 	{ "Invalid tid", &parent_tgid, &invalid_pid, SIGUSR1, EINVAL },
87 	{ "Invalid signal", &parent_tgid, &parent_tid, -1, EINVAL },
88 	{ "Defunct tid", &parent_tgid, &defunct_tid, SIGUSR1, ESRCH },
89 	{ "Defunct tgid", &defunct_tid, &child_tid, SIGUSR1, ESRCH },
90 	{ "Valid tgkill call", &parent_tgid, &child_tid, SIGUSR1, 0 },
91 };
92 
run(unsigned int i)93 static void run(unsigned int i)
94 {
95 	const struct testcase *tc = &testcases[i];
96 
97 	TEST(sys_tgkill(*tc->tgid, *tc->tid, tc->sig));
98 	if (tc->err) {
99 		if (TST_RET < 0 && TST_ERR == tc->err)
100 			tst_res(TPASS | TTERRNO, "%s failed as expected",
101 				tc->desc);
102 		else
103 			tst_res(TFAIL | TTERRNO,
104 				"%s should have failed with %s", tc->desc,
105 				tst_strerrno(tc->err));
106 	} else {
107 		if (TST_RET == 0)
108 			tst_res(TPASS, "%s succeeded", tc->desc);
109 		else
110 			tst_res(TFAIL | TTERRNO, "%s failed", tc->desc);
111 	}
112 }
113 
114 static struct tst_test test = {
115 	.tcnt = ARRAY_SIZE(testcases),
116 	.needs_checkpoints = 1,
117 	.setup = setup,
118 	.cleanup = cleanup,
119 	.test = run,
120 };
121