This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH 1/3] support: Add support_process_state_wait


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>
> 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]