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