From patchwork Fri Sep 25 14:03:51 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 522837 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4846A14010F for ; Sat, 26 Sep 2015 00:21:32 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b=AtzfdmN9; dkim-atps=neutral Received: from localhost ([::1]:42116 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZfTsQ-0000pY-3U for incoming@patchwork.ozlabs.org; Fri, 25 Sep 2015 10:21:30 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41762) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZfTc9-00075I-C6 for qemu-devel@nongnu.org; Fri, 25 Sep 2015 10:04:45 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZfTc7-0003hD-Dn for qemu-devel@nongnu.org; Fri, 25 Sep 2015 10:04:41 -0400 Received: from mail-wi0-x22c.google.com ([2a00:1450:400c:c05::22c]:37812) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZfTc7-0003gu-40 for qemu-devel@nongnu.org; Fri, 25 Sep 2015 10:04:39 -0400 Received: by wicfx3 with SMTP id fx3so21034499wic.0 for ; Fri, 25 Sep 2015 07:04:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; bh=mnzawdmk1XvdqMBEq31tJY2ZZbmvgDO9Qz8UvLKvsGE=; b=AtzfdmN9WfxDOw7X+qkIDP4FzukiDWrlDRFZ6pNIvG8VrfHs+Nu5328ud3EYAA1dcr ZsUyhk8ZwuuTrvMne5wGXcuV5fR3v9eb+gYAneU+ohWwINVbmVnNx1gGHbet3juviK+Z XpNqKY6YIA+/tkdejPowIr/Za8e++CepC1qgLrP2gRdshGoGaMFe56KdScFd5kwbN1st x/mhkUCjqV7czHG52nskiJckUIjJMWaI6PA2NoA64uX3fSKwpJxeGuSDgllSOWZoE63P swOh0N5l6C1JtZRpRk0vZKBOYhWKzyxiB57mBfGSo+l10ODTgCu+IZSORXvNEiHA0h2/ lRpg== X-Received: by 10.194.94.71 with SMTP id da7mr6648944wjb.8.1443189878495; Fri, 25 Sep 2015 07:04:38 -0700 (PDT) Received: from localhost ([149.6.167.210]) by smtp.gmail.com with ESMTPSA id l1sm3544534wjx.13.2015.09.25.07.04.37 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 25 Sep 2015 07:04:37 -0700 (PDT) From: marcandre.lureau@redhat.com To: qemu-devel@nongnu.org Date: Fri, 25 Sep 2015 16:03:51 +0200 Message-Id: <1443189844-20341-24-git-send-email-marcandre.lureau@redhat.com> X-Mailer: git-send-email 2.4.3 In-Reply-To: <1443189844-20341-1-git-send-email-marcandre.lureau@redhat.com> References: <1443189844-20341-1-git-send-email-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a00:1450:400c:c05::22c Cc: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , armbru@redhat.com, mdroth@linux.vnet.ibm.com Subject: [Qemu-devel] [PATCH 23/36] qmp: use a return callback for the command reply X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Marc-André Lureau Introduce QmpDispatchReturn, a callback called when a command reply is ready to be sent. Future patches will extend the concept to allow async replies. QmpReturn and associated functions is used internally for sync fonctions, but will be the basis of a async context (the dispatch return callback and the top response dict). Signed-off-by: Marc-André Lureau --- include/qapi/qmp/dispatch.h | 14 +++++++++++-- monitor.c | 13 ++++++++---- qapi/qmp-dispatch.c | 51 ++++++++++++++++++++++++++++++++++----------- qga/main.c | 22 +++++++++---------- tests/test-qmp-commands.c | 42 ++++++++++++++++++++----------------- 5 files changed, 94 insertions(+), 48 deletions(-) diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h index 96de3bf..b62acba 100644 --- a/include/qapi/qmp/dispatch.h +++ b/include/qapi/qmp/dispatch.h @@ -18,6 +18,14 @@ #include "qapi/qmp/qdict.h" #include "qapi/error.h" +typedef void (QmpDispatchReturn) (QObject *rsp, void *opaque); + +typedef struct QmpReturn { + QDict *rsp; + QmpDispatchReturn *return_cb; + void *opaque; +} QmpReturn; + typedef void (QmpCommandFunc)(QDict *, QObject **, Error **); typedef enum QmpCommandType @@ -44,7 +52,8 @@ typedef struct QmpCommand void qmp_register_command(const char *name, QmpCommandFunc *fn, QmpCommandOptions options); QmpCommand *qmp_find_command(const char *name); -QObject *qmp_dispatch(QObject *request, QDict *rsp); +void qmp_dispatch(QObject *request, QDict *rsp, + QmpDispatchReturn *return_cb, void *opaque); void qmp_disable_command(const char *name); void qmp_enable_command(const char *name); bool qmp_command_is_enabled(const QmpCommand *cmd); @@ -53,6 +62,7 @@ bool qmp_has_success_response(const QmpCommand *cmd); QObject *qmp_build_error_object(Error *err); typedef void (*qmp_cmd_callback_fn)(QmpCommand *cmd, void *opaque); void qmp_for_each_command(qmp_cmd_callback_fn fn, void *opaque); +void qmp_return(QmpReturn *qret, QObject *cmd_rsp); +void qmp_return_error(QmpReturn *qret, Error *err); #endif - diff --git a/monitor.c b/monitor.c index d7ee509..677061d 100644 --- a/monitor.c +++ b/monitor.c @@ -3570,6 +3570,13 @@ static QDict *qmp_check_input_obj(QObject *input_obj, Error **errp) return input_dict; } +static void qmp_dispatch_return(QObject *rsp, void *opaque) +{ + Monitor *mon = opaque; + + monitor_json_emitter(mon, rsp); +} + static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) { QObject *req, *rsp, *id = NULL; @@ -3606,15 +3613,13 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) goto err_out; } - rsp = qmp_dispatch(req, rqdict); + qmp_dispatch(req, rqdict, qmp_dispatch_return, mon); + rsp = NULL; err_out: if (err) { qdict_put_obj(rqdict, "error", qmp_build_error_object(err)); error_free(err); - } - - if (rsp) { monitor_json_emitter(mon, rsp); } diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index d2ae5f0..263ab65 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -60,7 +60,7 @@ static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp) return dict; } -static QObject *do_qmp_dispatch(QObject *request, Error **errp) +static QObject *do_qmp_dispatch(QObject *request, QmpReturn *qret, Error **errp) { Error *local_err = NULL; const char *command; @@ -118,23 +118,50 @@ QObject *qmp_build_error_object(Error *err) error_get_pretty(err)); } -QObject *qmp_dispatch(QObject *request, QDict *rsp) +static void do_qmp_return(QmpReturn *qret) +{ + QDict *rsp = qret->rsp; + + qret->return_cb(QOBJECT(rsp), qret->opaque); + + qobject_decref(QOBJECT(rsp)); + g_free(qret); +} + +void qmp_return(QmpReturn *qret, QObject *cmd_rsp) +{ + qdict_put_obj(qret->rsp, "return", cmd_rsp); + + do_qmp_return(qret); +} + +void qmp_return_error(QmpReturn *qret, Error *err) +{ + qdict_put_obj(qret->rsp, "error", qmp_build_error_object(err)); + error_free(err); + + do_qmp_return(qret); +} + +void qmp_dispatch(QObject *request, QDict *rsp, + QmpDispatchReturn *return_cb, void *opaque) { Error *err = NULL; + QmpReturn *qret = g_new0(QmpReturn, 1); QObject *ret; - ret = do_qmp_dispatch(request, &err); + assert(return_cb); + + qret->rsp = rsp ?: qdict_new(); + qret->return_cb = return_cb; + qret->opaque = opaque; + + ret = do_qmp_dispatch(request, qret, &err); - rsp = rsp ?: qdict_new(); if (err) { - qdict_put_obj(rsp, "error", qmp_build_error_object(err)); - error_free(err); + assert(!ret); + qmp_return_error(qret, err); } else if (ret) { - qdict_put_obj(rsp, "return", ret); - } else { - QDECREF(rsp); - return NULL; + qmp_return(qret, ret); } - - return QOBJECT(rsp); } diff --git a/qga/main.c b/qga/main.c index bfcde0b..21dba8f 100644 --- a/qga/main.c +++ b/qga/main.c @@ -546,21 +546,21 @@ static int send_response(GAState *s, QObject *payload) return 0; } -static void process_command(GAState *s, QDict *req) +static void dispatch_return_cb(QObject *rsp, void *opaque) { - QObject *rsp = NULL; - int ret; + GAState *s = opaque; + int ret = send_response(s, rsp); + + if (ret) { + g_warning("error sending response: %s", strerror(ret)); + } +} +static void process_command(GAState *s, QDict *req) +{ g_assert(req); g_debug("processing command"); - rsp = qmp_dispatch(QOBJECT(req), NULL); - if (rsp) { - ret = send_response(s, rsp); - if (ret) { - g_warning("error sending response: %s", strerror(ret)); - } - qobject_decref(rsp); - } + qmp_dispatch(QOBJECT(req), NULL, dispatch_return_cb, s); } /* handle requests/control events coming in over the channel */ diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c index 068db21..64d26af 100644 --- a/tests/test-qmp-commands.c +++ b/tests/test-qmp-commands.c @@ -76,53 +76,57 @@ __org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a, return ret; } +static void dispatch_cmd_return(QObject *resp, void *opaque) +{ + assert(resp != NULL); + assert(!qdict_haskey(qobject_to_qdict(resp), "error")); +} /* test commands with no input and no return value */ static void test_dispatch_cmd(void) { QDict *req = qdict_new(); - QObject *resp; qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd"))); - resp = qmp_dispatch(QOBJECT(req), NULL); - assert(resp != NULL); - assert(!qdict_haskey(qobject_to_qdict(resp), "error")); + qmp_dispatch(QOBJECT(req), NULL, dispatch_cmd_return, NULL); - qobject_decref(resp); QDECREF(req); } +static void dispatch_cmd_error_return(QObject *resp, void *opaque) +{ + assert(resp != NULL); + assert(qdict_haskey(qobject_to_qdict(resp), "error")); +} + /* test commands that return an error due to invalid parameters */ static void test_dispatch_cmd_error(void) { QDict *req = qdict_new(); - QObject *resp; qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2"))); - resp = qmp_dispatch(QOBJECT(req), NULL); - assert(resp != NULL); - assert(qdict_haskey(qobject_to_qdict(resp), "error")); + qmp_dispatch(QOBJECT(req), NULL, dispatch_cmd_error_return, NULL); - qobject_decref(resp); QDECREF(req); } -static QObject *test_qmp_dispatch(QDict *req) -{ - QObject *resp_obj; - QDict *resp; - QObject *ret; +static QObject *ret; - resp_obj = qmp_dispatch(QOBJECT(req), NULL); - assert(resp_obj); - resp = qobject_to_qdict(resp_obj); +static void qmp_dispatch_return(QObject *resp_obj, void *opaque) +{ + QDict *resp = qobject_to_qdict(resp_obj); assert(resp && !qdict_haskey(resp, "error")); ret = qdict_get(resp, "return"); assert(ret); qobject_incref(ret); - qobject_decref(resp_obj); +} + +static QObject *test_qmp_dispatch(QDict *req) +{ + qmp_dispatch(QOBJECT(req), NULL, qmp_dispatch_return, NULL); + return ret; }