[PATCH 1/3] support: Add support_process_state_wait
Adhemerval Zanella
adhemerval.zanella@linaro.org
Fri Dec 20 12:36:00 GMT 2019
Ping.
On 20/11/2019 11:15, Adhemerval Zanella wrote:
> It allows parent process to wait for children state using a polling
> strategy over procfs on Linux. The polling is used over ptrace to
> avoid the need to handle signals on the target pid and to handle some
> system specific limitations (such as YAMA).
>
> The polling has some limitations, such as resource consumption due
> the procfs read in a loop and the lack of synchronization after the
> state is obtained.
>
> The interface idea is to simplify some sleep synchronization in waitid
> tests.
> ---
> support/Makefile | 2 +
> support/process_state.h | 41 +++++++++++
> support/support_process_state.c | 89 ++++++++++++++++++++++++
> support/tst-support-process_state.c | 101 ++++++++++++++++++++++++++++
> 4 files changed, 233 insertions(+)
> create mode 100644 support/process_state.h
> create mode 100644 support/support_process_state.c
> create mode 100644 support/tst-support-process_state.c
>
> diff --git a/support/Makefile b/support/Makefile
> index 23c6d74627..b0d28200af 100644
> --- a/support/Makefile
> +++ b/support/Makefile
> @@ -56,6 +56,7 @@ libsupport-routines = \
> support_format_hostent \
> support_format_netent \
> support_isolate_in_subprocess \
> + support_process_state \
> support_ptrace \
> support_openpty \
> support_paths \
> @@ -223,6 +224,7 @@ tests = \
> tst-support_capture_subprocess \
> tst-support_descriptors \
> tst-support_format_dns_packet \
> + tst-support-process_state \
> tst-support_quote_blob \
> tst-support_quote_string \
> tst-support_record_failure \
> diff --git a/support/process_state.h b/support/process_state.h
> new file mode 100644
> index 0000000000..d616f0e3e6
> --- /dev/null
> +++ b/support/process_state.h
> @@ -0,0 +1,41 @@
> +/* Wait for process state.
> + Copyright (C) 2019 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#ifndef SUPPORT_PROCESS_STATE_H
> +#define SUPPORT_PROCESS_STATE_H
> +
> +#include <sys/types.h>
> +
> +enum process_state_t
> +{
> + process_state_running = 0x01, /* R (running) */
> + process_state_sleeping = 0x02, /* S (sleeping) */
> + process_state_disk_sleep = 0x04, /* D (disk sleep) */
> + process_state_stopped = 0x08, /* T (stopped) */
> + process_state_tracing_stop = 0x10, /* t (tracing stop) */
> + process_state_dead = 0x20, /* X (dead) */
> + process_state_zombie = 0x40, /* Z (zombie) */
> + process_state_parked = 0x80, /* P (parked) */
> +};
> +
> +/* Wait for process PID to reach state STATE. It can be a combination of
> + multiple possible states ('process_state_running | process_state_sleeping')
> + where the function return when any of these state are observed. */
> +void support_process_state_wait (pid_t pid, enum process_state_t state);
> +
> +#endif
> diff --git a/support/support_process_state.c b/support/support_process_state.c
> new file mode 100644
> index 0000000000..77c684c49c
> --- /dev/null
> +++ b/support/support_process_state.c
> @@ -0,0 +1,89 @@
> +/* Wait for process state.
> + Copyright (C) 2019 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include <stdio.h>
> +#include <fcntl.h>
> +#include <time.h>
> +
> +#include <array_length.h>
> +
> +#include <support/process_state.h>
> +#include <support/xunistd.h>
> +#include <support/check.h>
> +
> +void
> +support_process_state_wait (pid_t pid, enum process_state_t state)
> +{
> +#ifdef __linux__
> + /* For Linux it does a polling check on /proc/<pid>/status checking on
> + third field. */
> +
> + /* It mimics the kernel states from fs/proc/array.c */
> + static struct process_states_t
> + {
> + enum process_state_t s;
> + char v;
> + } process_states[] = {
> + { process_state_running, 'R' },
> + { process_state_sleeping, 'S' },
> + { process_state_disk_sleep, 'D' },
> + { process_state_stopped, 'T' },
> + { process_state_tracing_stop, 't' },
> + { process_state_dead, 'X' },
> + { process_state_zombie, 'Z' },
> + { process_state_parked, 'P' },
> + };
> +
> + char proc_path[sizeof ("/proc/" + 3) * sizeof (pid_t) + sizeof ("/stat")
> + + 1];
> + snprintf (proc_path, sizeof (proc_path), "/proc/%i/stat", pid);
> +
> + int fd = xopen (proc_path, O_RDONLY, 0600);
> +
> + char statbuf[3 * sizeof (pid_t) /* pid. */
> + + 2 /* ' (' */
> + + 64 /* task name. */
> + + 2 /* ' )' */
> + + 1 /* <state>, 1 char. */
> + + 1]; /* Final \0. */
> + for (;;)
> + {
> + ssize_t ret = read (fd, statbuf, sizeof (statbuf) - 1);
> + TEST_VERIFY (ret >= 0);
> + statbuf[ret] = '\0';
> +
> + char cur_state;
> + int sret = sscanf (statbuf, "%*i %*s %c", &cur_state);
> + TEST_VERIFY (sret == 1);
> +
> + for (size_t i = 0; i < array_length (process_states); ++i)
> + if (state & process_states[i].s && cur_state == process_states[i].v)
> + {
> + close (fd);
> + return;
> + }
> +
> + xlseek (fd, 0, SEEK_SET);
> + nanosleep (&(struct timespec) { 0, 10000000 }, NULL);
> + }
> +
> + close (fd);
> +#else
> + sleep (2);
> +#endif
> +}
> diff --git a/support/tst-support-process_state.c b/support/tst-support-process_state.c
> new file mode 100644
> index 0000000000..3482f12fa5
> --- /dev/null
> +++ b/support/tst-support-process_state.c
> @@ -0,0 +1,101 @@
> +/* Wait for process state tests.
> + Copyright (C) 2019 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include <stdio.h>
> +#include <sys/wait.h>
> +#include <unistd.h>
> +#include <errno.h>
> +
> +#include <support/test-driver.h>
> +#include <support/process_state.h>
> +#include <support/check.h>
> +#include <support/xsignal.h>
> +#include <support/xunistd.h>
> +
> +static void
> +sigusr1_handler (int signo)
> +{
> +}
> +
> +static void
> +test_child (void)
> +{
> + xsignal (SIGUSR1, sigusr1_handler);
> +
> + raise (SIGSTOP);
> +
> + TEST_COMPARE (pause (), -1);
> + TEST_COMPARE (errno, EINTR);
> +
> + while (1)
> + asm ("");
> +}
> +
> +static int
> +do_test (void)
> +{
> + pid_t pid = xfork ();
> + if (pid == 0)
> + {
> + test_child ();
> + _exit (127);
> + }
> +
> + /* Adding process_state_tracing_stop ('t') allows the test to work under
> + trace programs such as ptrace. */
> + enum process_state_t stop_state = process_state_stopped
> + | process_state_tracing_stop;
> +
> + if (test_verbose)
> + printf ("info: waiting pid %d, state_stopped/state_tracing_stop\n",
> + (int) pid);
> + support_process_state_wait (pid, stop_state);
> +
> + if (kill (pid, SIGCONT) != 0)
> + FAIL_RET ("kill (%d, SIGCONT): %m\n", pid);
> +
> + if (test_verbose)
> + printf ("info: waiting pid %d, state_sleeping\n", (int) pid);
> + support_process_state_wait (pid, process_state_sleeping);
> +
> + if (kill (pid, SIGUSR1) != 0)
> + FAIL_RET ("kill (%d, SIGUSR1): %m\n", pid);
> +
> + if (test_verbose)
> + printf ("info: waiting pid %d, state_running\n", (int) pid);
> + support_process_state_wait (pid, process_state_running);
> +
> + if (kill (pid, SIGKILL) != 0)
> + FAIL_RET ("kill (%d, SIGKILL): %m\n", pid);
> +
> + if (test_verbose)
> + printf ("info: waiting pid %d, state_zombie\n", (int) pid);
> + support_process_state_wait (pid, process_state_zombie);
> +
> + siginfo_t info;
> + int r = waitid (P_PID, pid, &info, WEXITED);
> + TEST_COMPARE (r, 0);
> + TEST_COMPARE (info.si_signo, SIGCHLD);
> + TEST_COMPARE (info.si_code, CLD_KILLED);
> + TEST_COMPARE (info.si_status, SIGKILL);
> + TEST_COMPARE (info.si_pid, pid);
> +
> + return 0;
> +}
> +
> +#include <support/test-driver.c>
>
More information about the Libc-alpha
mailing list