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