binutils-gdb/gdb/testsuite/gdb.base/vfork-follow-parent.c
Simon Marchi b8b5466f0d gdb/testsuite: fix intermittent failure in gdb.base/vfork-follow-parent.exp
Tom de Vries reported some failures in this test:

    continue
    Continuing.
    [New inferior 2 (process 14967)]

    Thread 1.1 "vfork-follow-pa" hit Breakpoint 2, break_parent () at /home/vries/gdb_versions/devel/src/gdb/testsuite/gdb.base/vfork-follow-parent.c:23
    23	}
    (gdb) FAIL: gdb.base/vfork-follow-parent.exp: resolution_method=schedule-multiple: continue to end of inferior 2
    inferior 1
    [Switching to inferior 1 [process 14961] (/home/vries/gdb_versions/devel/build/gdb/testsuite/outputs/gdb.base/vfork-follow-parent/vfork-follow-parent)]
    [Switching to thread 1.1 (process 14961)]
    #0  break_parent () at /home/vries/gdb_versions/devel/src/gdb/testsuite/gdb.base/vfork-follow-parent.c:23
    23	}
    (gdb) PASS: gdb.base/vfork-follow-parent.exp: resolution_method=schedule-multiple: inferior 1
    continue
    Continuing.
    [Inferior 2 (process 14967) exited normally]
    (gdb) FAIL: gdb.base/vfork-follow-parent.exp: resolution_method=schedule-multiple: continue to break_parent (the program exited)

Here, we continue both the vfork parent and child, since
schedule-multiple is on.  The child exits, which un-freezes the parent
and makes an exit event available to GDB.  We expect GDB to consume this
exit event and present it to the user.  Here, we see that GDB shows the
parent hitting a breakpoint before showing the child exit.

Because of the vfork, we know that chronologically, the child exiting
must have happend before the parent hitting a breakpoint.  However,
scheduling being what it is, it is possible for the parent to un-freeze
and exit quickly, such that when GDB pulls events out of the kernel,
exit events for both processes are available.  And then, GDB may chose
at random to return the one for the parent first.  This is what I
imagine what causes the failure shown above.

We could change the test to expect both possible outcomes, but I wanted
to avoid complicating the .exp file that way.  Instead, add a variable
that the parent loops on that we set only after we confirmed the exit of
the child.  That should ensure that the order is always the same.

Note that I wasn't able to reproduce the failure, so I can't tell if
this fix really fixes the problem.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=29021
Change-Id: Ibc8e527e0e00dac54b22021fe4d9d8ab0f3b28ad
2022-04-05 08:15:23 -04:00

47 lines
1.2 KiB
C

/* This testcase is part of GDB, the GNU debugger.
Copyright 2021-2022 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <unistd.h>
static volatile int unblock_parent = 0;
static void
break_parent (void)
{
}
int
main (void)
{
alarm (30);
if (vfork () != 0)
{
/* We want to guarantee that GDB processes the child exit event before
the parent's breakpoint hit event. Make the parent wait on this
variable that is eventually set by the test. */
while (!unblock_parent)
usleep (1000);
break_parent ();
}
else
_exit (0);
return 0;
}