[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH v3 05/15] qemu-iotests: delay QMP socket timers
From: |
Max Reitz |
Subject: |
Re: [PATCH v3 05/15] qemu-iotests: delay QMP socket timers |
Date: |
Mon, 3 May 2021 17:02:40 +0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.8.1 |
On 30.04.21 23:03, Emanuele Giuseppe Esposito wrote:
On 30/04/2021 13:59, Max Reitz wrote:
On 14.04.21 19:03, Emanuele Giuseppe Esposito wrote:
Attaching a gdbserver implies that the qmp socket
should wait indefinitely for an answer from QEMU.
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
---
python/qemu/machine.py | 3 +++
tests/qemu-iotests/iotests.py | 10 +++++++++-
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/python/qemu/machine.py b/python/qemu/machine.py
index 12752142c9..d6142271c2 100644
--- a/python/qemu/machine.py
+++ b/python/qemu/machine.py
@@ -409,6 +409,9 @@ def _launch(self) -> None:
stderr=subprocess.STDOUT,
shell=False,
close_fds=False)
+
+ if 'gdbserver' in self._wrapper:
+ self._qmp_timer = None
Why doesn’t __init__() evaluate this? This here doesn’t feel like the
right place for it. If we want to evaluate it here, self._qmp_timer
shouldn’t exist, and instead the timeout should be a _post_launch()
parameter. (Which I would have nothing against, by the way.)
Uhm.. I got another comment in a previous version where for the "event"
callbacks it was better a property than passing around a parameter.
Which I honestly agree.
I think that comment was in the sense of providing a default value,
which can be expressed by having a property that is set in __init__.
I don’t have anything against making this a property, but I also don’t
have anything against making it a _post_launch() parameter. I could
even live with both, i.e. set _qmp_timer to 15 in __init__, then have a
_post_launch parameter, and pass either self._qmp_timer or None if
self._wrapper includes 'gdbserver'.
What I do mind is that I don’t understand why the property is modified
here. The value of self._qmp_timer is supposed to be 15 by default and
None if self._wrapper includes 'gdbserver'. It should thus be changed
to None the moment self._wrapper is made to include 'gdbserver'.
Because self._wrapper is set only in __init__, this should happen in
__init__.
What should __init__() do? The check here is to see if the invocation
has gdb (and a couple of patches ahead also valgrind), to remove the timer.
If I understand what you mean, you want something like
def __init__(self, timer):
Oh, no. We can optionally do that perhaps later, but what I meant is
just to put this in __init__() (without adding any parameters to it):
self._qmp_timer = 15.0 if 'gdbserver' not in self._wrapper else None
I think self._qmp_timer should always reflect what timeout we are going
to use when a VM is launched. So if the conditions influencing the
timeout change, it should be updated immediately to reflect this. The
only condition we have right now is the content of self._wrapper, which
is only set in __init__, so self._qmp_timer should be set once in
__init__ and not changed afterwards.
That sounds academic, but imagine what would happen if we had a
set_qmp_timer() method: The timout could be adjusted, but launch() would
just ignore it and update the property, even though the conditions
influencing the timout didn’t change between set_qmp_timer() and launch().
Or if we had a get_qmp_timer(); a caller would read a timeout of 15.0
before launch(), even though the timeout is going to be None.
Therefore, I think a property should not be updated just before it is
read, but instead when any condition that’s supposed to influence its
value changes.
I suggested making it a parameter because updating a property when
reading it sounds like it should be a parameter instead. I.e., one
would say
def __init__():
self._qmp_timeout_default = 15.0
def post_launch(qmp_timeout):
self._qmp.accept(qmp_timeout)
def launch(self):
...
qmp_timeout = None if 'gdbserver' in self._wrapper \
else self._qmp_timout_default
self.post_launch(qmp_timeout)
Which is basically the structure your patch has, which gave me the idea.
[...]
self._post_launch()
def _early_cleanup(self) -> None:
diff --git a/tests/qemu-iotests/iotests.py
b/tests/qemu-iotests/iotests.py
index 05d0dc0751..380527245e 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
[...]
@@ -684,6 +687,11 @@ def qmp_to_opts(self, obj):
output_list += [key + '=' + obj[key]]
return ','.join(output_list)
+ def get_qmp_events(self, wait: bool = False) -> List[QMPMessage]:
+ if qemu_gdb:
+ wait = 0.0
[...]
Second, I don’t understand this. If the caller wants to block waiting
on an event, then that should have nothing to do with whether we have
gdb running or not. As far as I understand, setting wait to 0.0 is
the same as wait = False, i.e. we don’t block and just return None
immediately if there is no pending event.
You're right, this might not be needed here. The problem I had was that
calling gdb and pausing at a breakpoint or something for a while would
make the QMP socket timeout, thus aborting the whole test. In order to
avoid that, I need to stop or delay timers.
I can't remember why I added this check here. At some point I am sure
the test was failing because of socket timeout expiration, but I cannot
reproduce the problem when commenting out this check above in
get_qmp_events. The other check in patch 3 should be enough.
Hm, ok. I’d guessed that you intended the wait=0.0 or wait=False to
mean that we get an infinite timeout (i.e., no timeout), but that’s
exactly why I didn’t get it. wait=0.0 doesn’t give an infinite timeout,
but instead basically times out immediately.
Max
- Re: [PATCH v3 05/15] qemu-iotests: delay QMP socket timers,
Max Reitz <=