> On May 12, 2020, at 6:21 AM, Stefan Hajnoczi <stefa...@redhat.com> wrote:
> 
> On Wed, Apr 22, 2020 at 09:13:47PM -0700, elena.ufimts...@oracle.com wrote:
>> From: Jagannathan Raman <jag.ra...@oracle.com>
>> 
>> In some cases, for example MMIO read, QEMU has to wait for the remote to
>> complete a command before proceeding. An eventfd based mechanism is
>> added to synchronize QEMU & remote process.
> 
> Why are temporary eventfds used instead of sending a reply message from
> the remote device program back to QEMU?

Originally, we were envisioning a scenario where the remote process would
interrupt QEMU with a message. We used separate eventfds to distinguish
the two.

> 
>> Signed-off-by: John G Johnson <john.g.john...@oracle.com>
>> Signed-off-by: Jagannathan Raman <jag.ra...@oracle.com>
>> Signed-off-by: Elena Ufimtseva <elena.ufimts...@oracle.com>
>> ---
>> include/io/mpqemu-link.h |  7 +++++
>> io/mpqemu-link.c         | 61 ++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 68 insertions(+)
>> 
>> diff --git a/include/io/mpqemu-link.h b/include/io/mpqemu-link.h
>> index af401e640c..ef95599bca 100644
>> --- a/include/io/mpqemu-link.h
>> +++ b/include/io/mpqemu-link.h
>> @@ -124,4 +124,11 @@ void mpqemu_link_set_callback(MPQemuLinkState *s,
>> void mpqemu_start_coms(MPQemuLinkState *s, MPQemuChannel* chan);
>> bool mpqemu_msg_valid(MPQemuMsg *msg);
>> 
>> +#define GET_REMOTE_WAIT eventfd(0, EFD_CLOEXEC)
>> +#define PUT_REMOTE_WAIT(wait) close(wait)
> 
> Hiding this in macros makes the code harder to understand.
> 
> Why is an eventfd necessary instead of a reply message? It's simpler and
> probably faster to use a reply message instead of creating and passing
> temporary eventfds.

OK, got it.

> 
>> +#define PROXY_LINK_WAIT_DONE 1
>> +
>> +uint64_t wait_for_remote(int efd);
>> +void notify_proxy(int fd, uint64_t val);
>> +
>> #endif
>> diff --git a/io/mpqemu-link.c b/io/mpqemu-link.c
>> index 48f53a8928..cc0a7aecd4 100644
>> --- a/io/mpqemu-link.c
>> +++ b/io/mpqemu-link.c
>> @@ -10,6 +10,7 @@
>> 
>> #include "qemu/osdep.h"
>> #include "qemu-common.h"
>> +#include <poll.h>
>> 
>> #include "qemu/module.h"
>> #include "io/mpqemu-link.h"
>> @@ -204,6 +205,66 @@ int mpqemu_msg_recv(MPQemuMsg *msg, MPQemuChannel *chan)
>>     return rc;
>> }
>> 
>> +/*
>> + * wait_for_remote() Synchronizes QEMU and the remote process. The maximum
>> + *                   wait time is 1s, after which the wait times out.
>> + *                   The function alse returns a 64 bit return value after
>> + *                   the wait. The function uses eventfd() to do the wait
>> + *                   and pass the return values. eventfd() can't return a
>> + *                   value of '0'. Therefore, all return values are offset
>> + *                   by '1' at the sending end, and corrected at the
>> + *                   receiving end.
>> + */
>> +
>> +uint64_t wait_for_remote(int efd)
>> +{
>> +    struct pollfd pfd = { .fd = efd, .events = POLLIN };
>> +    uint64_t val;
>> +    int ret;
>> +
>> +    ret = poll(&pfd, 1, 1000);
> 
> This 1 second blocking operation is not allowed in an event loop since
> it will stall any other event loop activity. If locks are held then
> other threads may also be stalled.
> 
> It's likely that this will need to change as part of the QEMU event loop
> integration. Caller code can be kept mostly unchanged if you use
> coroutines.

In case the remote process has hung or terminated, the 1 second timeout
ensures that the IO operation does not block for too long.

--
Jag

> 
>> +
>> +    switch (ret) {
>> +    case 0:
>> +        qemu_log_mask(LOG_REMOTE_DEBUG, "Error wait_for_remote: Timed 
>> out\n");
>> +        /* TODO: Kick-off error recovery */
>> +        return UINT64_MAX;
>> +    case -1:
>> +        qemu_log_mask(LOG_REMOTE_DEBUG, "Poll error wait_for_remote: %s\n",
>> +                      strerror(errno));
>> +        return UINT64_MAX;
>> +    default:
>> +        if (read(efd, &val, sizeof(val)) == -1) {
>> +            qemu_log_mask(LOG_REMOTE_DEBUG, "Error wait_for_remote: %s\n",
>> +                          strerror(errno));
>> +            return UINT64_MAX;
>> +        }
>> +    }
>> +
>> +    /*
>> +     * The remote process could write a non-zero value
>> +     * to the eventfd to wake QEMU up. However, the drawback of using 
>> eventfd
>> +     * for this purpose is that a return value of zero wouldn't wake QEMU 
>> up.
>> +     * Therefore, we offset the return value by one at the remote process 
>> and
>> +     * correct it in the QEMU end.
>> +     */
>> +    val = (val == UINT64_MAX) ? val : (val - 1);
>> +
>> +    return val;
>> +}
>> +
>> +void notify_proxy(int efd, uint64_t val)
>> +{
>> +    val = (val == UINT64_MAX) ? val : (val + 1);
>> +    ssize_t len = -1;
>> +
>> +    len = write(efd, &val, sizeof(val));
>> +    if (len == -1 || len != sizeof(val)) {
>> +        qemu_log_mask(LOG_REMOTE_DEBUG, "Error notify_proxy: %s\n",
>> +                      strerror(errno));
>> +    }
>> +}
>> +
>> static gboolean mpqemu_link_handler_prepare(GSource *gsrc, gint *timeout)
>> {
>>     g_assert(timeout);
>> -- 
>> 2.25.GIT
>> 


Reply via email to