android13/external/ltp/testcases/kernel/syscalls/clone3/clone301.c

186 lines
3.7 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2020 Viresh Kumar <viresh.kumar@linaro.org>
*/
/*\
* [Description]
*
* Basic clone3() test.
*/
#define _GNU_SOURCE
#include <stdlib.h>
#include <sys/wait.h>
#include "tst_test.h"
#include "lapi/clone.h"
#include "lapi/pidfd_send_signal.h"
#define CHILD_SIGNAL SIGUSR1
#define DATA 777
static int pidfd, child_tid, parent_tid, parent_received_signal;
static volatile int child_received_signal, child_data;
static struct clone_args *args;
static struct tcase {
uint64_t flags;
int exit_signal;
} tcases[] = {
{0, SIGCHLD},
{0, SIGUSR2},
{CLONE_FS, SIGCHLD},
{CLONE_NEWPID, SIGCHLD},
{CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_PIDFD, SIGCHLD},
};
static void parent_rx_signal(int sig)
{
parent_received_signal = sig;
}
static void child_rx_signal(int sig, siginfo_t *info, void *ucontext)
{
(void) ucontext;
child_received_signal = sig;
child_data = info->si_value.sival_int;
}
static struct sigaction psig_action = {
.sa_handler = parent_rx_signal,
};
static struct sigaction csig_action = {
.sa_sigaction = child_rx_signal,
.sa_flags = SA_SIGINFO,
};
static siginfo_t uinfo = {
.si_signo = CHILD_SIGNAL,
.si_code = SI_QUEUE,
.si_value.sival_int = DATA,
};
static void do_child(int clone_pidfd)
{
int count = 1000;
if (clone_pidfd) {
child_received_signal = 0;
child_data = 0;
SAFE_SIGACTION(CHILD_SIGNAL, &csig_action, NULL);
TST_CHECKPOINT_WAKE(0);
while (child_received_signal != CHILD_SIGNAL && --count)
usleep(100);
if (!child_received_signal) {
tst_res(TFAIL, "Child haven't got signal");
exit(0);
}
if (child_received_signal != CHILD_SIGNAL) {
tst_res(TFAIL, "Child got %s (%i) signal expected %s",
tst_strsig(child_received_signal),
child_received_signal,
tst_strsig(CHILD_SIGNAL));
exit(0);
}
tst_res(TPASS, "Child got correct signal %s",
tst_strsig(CHILD_SIGNAL));
if (child_data != DATA) {
tst_res(TFAIL, "Child got wrong si_value=%i expected %i",
child_data, DATA);
} else {
tst_res(TPASS, "Child got correct si_value");
}
}
exit(0);
}
static void run(unsigned int n)
{
struct tcase *tc = &tcases[n];
int status, clone_pidfd = tc->flags & CLONE_PIDFD;
pid_t pid;
args->flags = tc->flags;
args->pidfd = (uint64_t)(&pidfd);
args->child_tid = (uint64_t)(&child_tid);
args->parent_tid = (uint64_t)(&parent_tid);
args->exit_signal = tc->exit_signal;
args->stack = 0;
args->stack_size = 0;
args->tls = 0;
parent_received_signal = 0;
SAFE_SIGACTION(tc->exit_signal, &psig_action, NULL);
TEST(pid = clone3(args, sizeof(*args)));
if (pid < 0) {
tst_res(TFAIL | TTERRNO, "clone3() failed (%d)", n);
return;
}
if (!pid)
do_child(clone_pidfd);
/* Need to send signal to child process */
if (clone_pidfd) {
TST_CHECKPOINT_WAIT(0);
TEST(pidfd_send_signal(pidfd, CHILD_SIGNAL, &uinfo, 0));
if (TST_RET != 0) {
tst_res(TFAIL | TTERRNO, "pidfd_send_signal() failed");
return;
}
}
SAFE_WAITPID(pid, &status, __WALL);
if (!parent_received_signal) {
tst_res(TFAIL, "Parent haven't got signal");
return;
}
if (parent_received_signal != tc->exit_signal) {
tst_res(TFAIL, "Parent got %s (%i) signal expected %s",
tst_strsig(parent_received_signal),
parent_received_signal,
tst_strsig(tc->exit_signal));
return;
}
tst_res(TPASS, "Parent got correct signal %s",
tst_strsig(parent_received_signal));
}
static void setup(void)
{
clone3_supported_by_kernel();
uinfo.si_pid = getpid();
uinfo.si_uid = getuid();
}
static struct tst_test test = {
.tcnt = ARRAY_SIZE(tcases),
.test = run,
.setup = setup,
.needs_root = 1,
.needs_checkpoints = 1,
.bufs = (struct tst_buffers []) {
{&args, .size = sizeof(*args)},
{},
}
};