qtest_qmp_receive_dict() / qmp_fd_receive() QEMU

QDict *qtest_qmp_receive_dict(QTestState *s)
{
    // 通过 s->qmp_fd 来 receive 输出
    return qmp_fd_receive(s->qmp_fd);
}

QDict *qmp_fd_receive(int fd)
{
    QMPResponseParser qmp;
    bool log = getenv("QTEST_LOG") != NULL;

    qmp.response = NULL;
    json_message_parser_init(&qmp.parser, qmp_response, &qmp, NULL);

    while (!qmp.response) {
        ssize_t len;
        char c;

        // 一次接收一个 char
        len = recv(fd, &c, 1, 0);

        // error handling...
        // ...

        if (log)
            g_assert(write(2, &c, 1) == 1);

        // 把接收到的 char feed 到 JsonParser 当中。
        // JsonParser 只是一个 parser,并不会存储任何信息。
        // 解析完成后存储到了 qmp.response 当中。
        json_message_parser_feed(&qmp.parser, &c, 1);
    }

    if (log)
        g_assert(write(2, "\n", 1) == 1);

    json_message_parser_destroy(&qmp.parser);
    return qmp.response;
}

struct QMPResponseParser QEMU

typedef struct {
    JSONMessageParser parser;
    // 注意这是一个 QDict。
    QDict *response;
} QMPResponseParser;

qtest_qmp_receive() QEMU

QDict *qtest_qmp_receive(QTestState *s)
{
    while (true) {
        QDict *response = qtest_qmp_receive_dict(s);

        if (!qdict_get_try_str(response, "event"))
            return response;

        if (!s->eventCB || !s->eventCB(s, qdict_get_str(response, "event"), response, s->eventData)) {
            /* Stash the event for a later consumption */
            // 一个关于 QDict 的 list
            s->pending_events = g_list_append(s->pending_events, response);
        }
    }
}

qtest_qmp_event_ref() QEMU

这个函数是把现在已经 stash 的 pending_events 处理完。

QDict *qtest_qmp_event_ref(QTestState *s, const char *event)
{
    while (s->pending_events) {
        GList *first = s->pending_events;
        QDict *response = (QDict *)first->data;

        s->pending_events = g_list_delete_link(s->pending_events, first);

        if (!strcmp(qdict_get_str(response, "event"), event))
            return response;

        qobject_unref(response);
    }

    return NULL;
}

qtest_qmp_eventwait_ref() QEMU

QDict *qtest_qmp_eventwait_ref(QTestState *s, const char *event)
{
    // 先处理已经有的 pending_events
    QDict *response = qtest_qmp_event_ref(s, event);

    if (response)
        return response;

    // 继续接收
    for (;;) {
        response = qtest_qmp_receive_dict(s);
        if ((qdict_haskey(response, "event")) &&
            (strcmp(qdict_get_str(response, "event"), event) == 0)) {
            return response;
        }
        qobject_unref(response);
    }
}