Commit e02b52ec authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

selftests: net: py: support ksft ready without wait



There's a common synchronization problem when a script (Python test)
uses a C program to set up some state (usually start a receiving
process for traffic). The script needs to know when the process
has fully initialized. The inverse of the problem exists for shutting
the process down - we need a reliable way to tell the process to exit.

We added helpers to do this safely in
commit 71477137 ("selftests: drv-net: add a way to wait for a local process")
unfortunately the two operations (wait for init, and shutdown) are
controlled by a single parameter (ksft_wait). Add support for using
ksft_ready without using the second fd for exit.

This is useful for programs which wait for a specific number of packets
to rx so exit_wait is a good match, but we still need to wait for init.

Reviewed-by: default avatarPetr Machata <petrm@nvidia.com>
Reviewed-by: default avatarWillem de Bruijn <willemb@google.com>
Reviewed-by: default avatarbreno Leitao <leitao@debian.org>
Link: https://patch.msgid.link/20251120021024.2944527-7-kuba@kernel.org


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 89268f7d
Loading
Loading
Loading
Loading
+12 −8
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@ class cmd:
    Use bkg() instead to run a command in the background.
    """
    def __init__(self, comm, shell=None, fail=True, ns=None, background=False,
                 host=None, timeout=5, ksft_wait=None):
                 host=None, timeout=5, ksft_ready=None, ksft_wait=None):
        if ns:
            comm = f'ip netns exec {ns} ' + comm

@@ -52,21 +52,25 @@ class cmd:
            # ksft_wait lets us wait for the background process to fully start,
            # we pass an FD to the child process, and wait for it to write back.
            # Similarly term_fd tells child it's time to exit.
            pass_fds = ()
            pass_fds = []
            env = os.environ.copy()
            if ksft_wait is not None:
                rfd, ready_fd = os.pipe()
                wait_fd, self.ksft_term_fd = os.pipe()
                pass_fds = (ready_fd, wait_fd, )
                env["KSFT_READY_FD"] = str(ready_fd)
                pass_fds.append(wait_fd)
                env["KSFT_WAIT_FD"]  = str(wait_fd)
                ksft_ready = True  # ksft_wait implies ready
            if ksft_ready is not None:
                rfd, ready_fd = os.pipe()
                pass_fds.append(ready_fd)
                env["KSFT_READY_FD"] = str(ready_fd)

            self.proc = subprocess.Popen(comm, shell=shell, stdout=subprocess.PIPE,
                                         stderr=subprocess.PIPE, pass_fds=pass_fds,
                                         env=env)
            if ksft_wait is not None:
                os.close(ready_fd)
                os.close(wait_fd)
            if ksft_ready is not None:
                os.close(ready_fd)
                msg = fd_read_timeout(rfd, ksft_wait)
                os.close(rfd)
                if not msg:
@@ -116,10 +120,10 @@ class bkg(cmd):
        with bkg("my_binary", ksft_wait=5):
    """
    def __init__(self, comm, shell=None, fail=None, ns=None, host=None,
                 exit_wait=False, ksft_wait=None):
                 exit_wait=False, ksft_ready=None, ksft_wait=None):
        super().__init__(comm, background=True,
                         shell=shell, fail=fail, ns=ns, host=host,
                         ksft_wait=ksft_wait)
                         ksft_ready=ksft_ready, ksft_wait=ksft_wait)
        self.terminate = not exit_wait and not ksft_wait
        self._exit_wait = exit_wait
        self.check_fail = fail