This test verifies the correct behavior of the fork() system call, which creates a child process by duplicating the parent process.
The test checks the following: - The child PID returned by fork() is present in /proc. - The child PID is different from the parent PID. - The memory allocated to a variable in the child process is independent of the parent process.
Test logs :
- Run without root TAP version 13 1..1 ok 1 # SKIP This test needs root to run!
- Run with root TAP version 13 1..1 # Inside the parent process. # Child PID got from fork() return : 56038 # Parent PID from getpid(): 56037 # Inside the child process. 1..2 ok 1 Child Pid from /proc and fork() matching ok 2 Child Pid != Parent pid 1..3 ok 3 After modification in child No effect on the value of 'var' in parent # Totals: pass:3 fail:0 xfail:0 xpass:0 skip:0 error:0
Signed-off-by: Shivam Chaudhary cvam0000@gmail.com ---
Here is my proposal for a new directory, /syscalls, to add syscall selftests, as there is currently no dedicated space for these tests. I encountered this issue while writing the test case for the delete_module syscall and was unsure where to place it. As a heads-up, the delete_module test is currently under review, and I would like to add it to this directory.
tools/testing/selftests/Makefile | 1 + tools/testing/selftests/syscalls/.gitignore | 1 + .../syscalls/fork_syscall/.gitignore | 1 + .../selftests/syscalls/fork_syscall/Makefile | 5 + .../syscalls/fork_syscall/fork_syscall.c | 151 ++++++++++++++++++ 5 files changed, 159 insertions(+) create mode 100644 tools/testing/selftests/syscalls/.gitignore create mode 100644 tools/testing/selftests/syscalls/fork_syscall/.gitignore create mode 100644 tools/testing/selftests/syscalls/fork_syscall/Makefile create mode 100644 tools/testing/selftests/syscalls/fork_syscall/fork_syscall.c
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 363d031a16f7..9265c17c5de3 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -97,6 +97,7 @@ TARGETS += sparc64 TARGETS += splice TARGETS += static_keys TARGETS += sync +TARGETS += syscalls/fork_syscall TARGETS += syscall_user_dispatch TARGETS += sysctl TARGETS += tc-testing diff --git a/tools/testing/selftests/syscalls/.gitignore b/tools/testing/selftests/syscalls/.gitignore new file mode 100644 index 000000000000..c7ae138d3f0c --- /dev/null +++ b/tools/testing/selftests/syscalls/.gitignore @@ -0,0 +1 @@ +// SPDX-License-Identifier: GPL-2.0 \ No newline at end of file diff --git a/tools/testing/selftests/syscalls/fork_syscall/.gitignore b/tools/testing/selftests/syscalls/fork_syscall/.gitignore new file mode 100644 index 000000000000..788cc1ff70bd --- /dev/null +++ b/tools/testing/selftests/syscalls/fork_syscall/.gitignore @@ -0,0 +1 @@ +# SPDX-License-Identifier: GPL-2.0-only \ No newline at end of file diff --git a/tools/testing/selftests/syscalls/fork_syscall/Makefile b/tools/testing/selftests/syscalls/fork_syscall/Makefile new file mode 100644 index 000000000000..56033a3d5a87 --- /dev/null +++ b/tools/testing/selftests/syscalls/fork_syscall/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 +TEST_GEN_PROGS := fork_syscall +CFLAGS += -Wall + +include ../lib.mk \ No newline at end of file diff --git a/tools/testing/selftests/syscalls/fork_syscall/fork_syscall.c b/tools/testing/selftests/syscalls/fork_syscall/fork_syscall.c new file mode 100644 index 000000000000..eab22831f7e1 --- /dev/null +++ b/tools/testing/selftests/syscalls/fork_syscall/fork_syscall.c @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* kselftest for fork() system call + * + * Summery : fork() system call is used to create a new process + * by duplicating an existing one. The new process, known as the + * child process, is a copy of the parent process. + * + * Child process is dublicate process but has different PID and + * memory allocation. + * + * About the test : With this test we are testing the following: + * - Child PID which fork() returns to Parent is present in /proc + * - Child PID is not same as Parent PID. + * - Memory allocation to a variable in child and parent process + * is different. +*/ + + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <dirent.h> +#include <ctype.h> + +#include "../../kselftest.h" + +// Function to check if a string is numeric (PID check) +int is_numeric(const char *str) { + while (*str) { + if (!isdigit(*str)) return 0; + str++; + } + return 1; +} + +// Function to find the child PID in /proc +pid_t find_child_pid(pid_t parent_pid) { + DIR *proc_dir = opendir("/proc"); + struct dirent *entry; + + if (proc_dir == NULL) { + perror("Failed to open /proc directory"); + ksft_exit_fail(); + return 1; + } + + // Iterate through the /proc directory to find PIDs + while ((entry = readdir(proc_dir)) != NULL) { + // Check if the entry is a PID + if (is_numeric(entry->d_name)) { + pid_t pid = atoi(entry->d_name); + + // Construct the path to /proc/<pid>/ + //stat to check the parent PID + + char path[40], buffer[100]; + snprintf(path, 40, "/proc/%d/stat", pid); + + FILE *stat_file = fopen(path, "r"); + if (stat_file != NULL) { + fgets(buffer, 100, stat_file); + fclose(stat_file); + + // The fourth field in /proc/<pid>/stat is the parent PID + pid_t ppid; + sscanf(buffer, "%*d %*s %*c %d", &ppid); + + if (ppid == parent_pid) { + closedir(proc_dir); + // Return the child PID if the parent PID matches + return pid; + } + } + } + } + + closedir(proc_dir); + + // Return -1 if no child PID was found + return -1; +} + +int main(void) { + + // Setting up kselftest framework + ksft_print_header(); + ksft_set_plan(1); + + // Check if test is run a root + if (geteuid()) { + ksft_test_result_skip("This test needs root to run!\n"); + return 1; + } + + // forking + pid_t pid = fork(); + + // Declare a variable in both parent and child processes + int var = 17; + + if (pid == -1) { + ksft_test_result_error("%s.\n", strerror(errno)); + ksft_finished(); + return 1; + + } else if (pid == 0) { + // This is the child process + ksft_print_msg("Inside the child process.\n"); + var = 1998; + + } else { + // This is the parent process + pid_t ppid=getpid(); + ksft_print_msg("Inside the parent process.\n"); + ksft_print_msg("Child PID got from fork() return : %d\n", pid); + ksft_print_msg("Parent PID from getpid(): %d\n",ppid); + + // Find the child PID in /proc + pid_t child_pid = find_child_pid(getpid()); + if (child_pid != -1) { + ksft_set_plan(2); + if(child_pid == pid && pid != ppid && var != 1998) { + ksft_test_result_pass("Child Pid from /proc and fork() matching\n"); + ksft_test_result_pass("Child Pid != Parent pid\n"); + ksft_set_plan(3); + ksft_test_result_pass( + "After modification in child No effect on the value of 'var' in parent\n"); + ksft_exit_pass(); + return 0; + } + else { + ksft_exit_fail(); + return 1; + } + } + else { + ksft_test_result_fail("Child Pid from /proc and fork() does not match"); + ksft_exit_fail(); + return 1; + } + + // Wait for the child process to finish + wait(NULL); + } + + return 0; +} +
On 10/22/24 14:42, Shivam Chaudhary wrote:
This test verifies the correct behavior of the fork() system call, which creates a child process by duplicating the parent process.
The test checks the following:
- The child PID returned by fork() is present in /proc.
- The child PID is different from the parent PID.
- The memory allocated to a variable in the child process is independent of the parent process.
Short log should incude the subsystem:
e.g: selftests: add test for fork() syscall
In anycase, I don't see any value to adding this test. fork() is a heavily used system call.
thanks, -- Shuah
On 24/10/24 2:15 AM, Shuah Khan wrote:
On 10/22/24 14:42, Shivam Chaudhary wrote:
This test verifies the correct behavior of the fork() system call, which creates a child process by duplicating the parent process.
The test checks the following:
- The child PID returned by fork() is present in /proc.
- The child PID is different from the parent PID.
- The memory allocated to a variable in the child process is independent
of the parent process.
Short log should incude the subsystem:
e.g: selftests: add test for fork() syscall
In anycase, I don't see any value to adding this test. fork() is a heavily used system call.
Thanks for responding Shuah,
Yes, you are correct that fork() is a heavily used syscall, that is why my concern is that
it could fail millions of other program that depends on fork() if any error or regression
occurs in the future. In my opinion, that is why we should test it every way possible.
thanks Shivam
On 10/23/24 15:11, Shivam Chaudhary wrote:
On 24/10/24 2:15 AM, Shuah Khan wrote:
On 10/22/24 14:42, Shivam Chaudhary wrote:
This test verifies the correct behavior of the fork() system call, which creates a child process by duplicating the parent process.
The test checks the following:
- The child PID returned by fork() is present in /proc.
- The child PID is different from the parent PID.
- The memory allocated to a variable in the child process is independent
of the parent process.
Short log should incude the subsystem:
e.g: selftests: add test for fork() syscall
In anycase, I don't see any value to adding this test. fork() is a heavily used system call.
Thanks for responding Shuah,
Yes, you are correct that fork() is a heavily used syscall, that is why my concern is that
it could fail millions of other program that depends on fork() if any error or regression
occurs in the future. In my opinion, that is why we should test it every way possible.
Sorry. I don't see any value in adding this test.
thanks, -- Shuah
linux-kselftest-mirror@lists.linaro.org