From patchwork Fri Apr 8 16:13:04 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 8784551 Return-Path: X-Original-To: patchwork-qemu-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id C04F29F659 for ; Fri, 8 Apr 2016 16:16:03 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id E7970202DD for ; Fri, 8 Apr 2016 16:16:02 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id CA3AF2011D for ; Fri, 8 Apr 2016 16:16:01 +0000 (UTC) Received: from localhost ([::1]:57033 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aoZ4j-00048j-2M for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Apr 2016 12:16:01 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:36994) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aoZ2A-0007jL-6x for qemu-devel@nongnu.org; Fri, 08 Apr 2016 12:13:23 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aoZ28-0002Nl-0r for qemu-devel@nongnu.org; Fri, 08 Apr 2016 12:13:22 -0400 Received: from mx1.redhat.com ([209.132.183.28]:44188) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aoZ27-0002ND-Ps for qemu-devel@nongnu.org; Fri, 08 Apr 2016 12:13:19 -0400 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 842713B756; Fri, 8 Apr 2016 16:13:19 +0000 (UTC) Received: from red.redhat.com (ovpn-113-199.phx2.redhat.com [10.3.113.199]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u38GDEGN012676; Fri, 8 Apr 2016 12:13:19 -0400 From: Eric Blake To: qemu-devel@nongnu.org Date: Fri, 8 Apr 2016 10:13:04 -0600 Message-Id: <1460131992-32278-12-git-send-email-eblake@redhat.com> In-Reply-To: <1460131992-32278-1-git-send-email-eblake@redhat.com> References: <1460131992-32278-1-git-send-email-eblake@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.24 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v14 11/19] qmp: Support explicit null during visits X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: armbru@redhat.com, Michael Roth Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Implement the new type_null() callback for the qmp input and output visitors. While we don't yet have a use for this in QAPI input (the generator will need some tweaks first), one usage is already envisioned: when changing blockdev parameters, it would be nice to have a difference between leaving a tuning parameter unchanged (omit that parameter from the struct) and to explicitly reset the parameter to its default without having to know what the default value is (specify the parameter with an explicit null value, which will require us to allow a QAPI alternate that chooses between the normal value and an explicit null). Meanwhile, the output visitor could already output explicit null via type_any, but this gives us finer control. At any rate, it's easy to test that we can round-trip an explicit null through manual use of visit_type_null(). Repurpose the test_visitor_out_empty test, particularly since a future patch will tighten semantics to forbid immediate use of qmp_output_get_qobject() without at least one visit_type_*. Signed-off-by: Eric Blake --- v14: rebase to header inclusion cleanups v13: no change v12: retitle and merge in output visitor support, move refcount tests to separate file [no v10, v11] v9: new patch --- qapi/qmp-input-visitor.c | 12 ++++++++++++ qapi/qmp-output-visitor.c | 7 +++++++ tests/check-qnull.c | 11 ++++++++++- tests/test-qmp-input-visitor.c | 16 ++++++++++++++++ tests/test-qmp-output-visitor.c | 9 +++++---- 5 files changed, 50 insertions(+), 5 deletions(-) diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c index 1820360..e5b412a 100644 --- a/qapi/qmp-input-visitor.c +++ b/qapi/qmp-input-visitor.c @@ -339,6 +339,17 @@ static void qmp_input_type_any(Visitor *v, const char *name, QObject **obj, *obj = qobj; } +static void qmp_input_type_null(Visitor *v, const char *name, Error **errp) +{ + QmpInputVisitor *qiv = to_qiv(v); + QObject *qobj = qmp_input_get_object(qiv, name, true); + + if (qobject_type(qobj) != QTYPE_QNULL) { + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", + "null"); + } +} + static void qmp_input_optional(Visitor *v, const char *name, bool *present) { QmpInputVisitor *qiv = to_qiv(v); @@ -382,6 +393,7 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj) v->visitor.type_str = qmp_input_type_str; v->visitor.type_number = qmp_input_type_number; v->visitor.type_any = qmp_input_type_any; + v->visitor.type_null = qmp_input_type_null; v->visitor.optional = qmp_input_optional; qmp_input_push(v, obj, NULL, NULL); diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c index 1f2a7ba..5681ad3 100644 --- a/qapi/qmp-output-visitor.c +++ b/qapi/qmp-output-visitor.c @@ -196,6 +196,12 @@ static void qmp_output_type_any(Visitor *v, const char *name, QObject **obj, qmp_output_add_obj(qov, name, *obj); } +static void qmp_output_type_null(Visitor *v, const char *name, Error **errp) +{ + QmpOutputVisitor *qov = to_qov(v); + qmp_output_add_obj(qov, name, qnull()); +} + /* Finish building, and return the root object. Will not be NULL. */ QObject *qmp_output_get_qobject(QmpOutputVisitor *qov) { @@ -246,6 +252,7 @@ QmpOutputVisitor *qmp_output_visitor_new(void) v->visitor.type_str = qmp_output_type_str; v->visitor.type_number = qmp_output_type_number; v->visitor.type_any = qmp_output_type_any; + v->visitor.type_null = qmp_output_type_null; QTAILQ_INIT(&v->stack); diff --git a/tests/check-qnull.c b/tests/check-qnull.c index b0fb1e6..43a222d 100644 --- a/tests/check-qnull.c +++ b/tests/check-qnull.c @@ -11,7 +11,9 @@ #include "qapi/qmp/qobject.h" #include "qemu-common.h" +#include "qapi/qmp-input-visitor.h" #include "qapi/qmp-output-visitor.h" +#include "qapi/error.h" /* * Public Interface test-cases @@ -37,15 +39,22 @@ static void qnull_visit_test(void) { QObject *obj; QmpOutputVisitor *qov; + QmpInputVisitor *qiv; g_assert(qnull_.refcnt == 1); + obj = qnull(); + qiv = qmp_input_visitor_new(obj); + qobject_decref(obj); + visit_type_null(qmp_input_get_visitor(qiv), NULL, &error_abort); + qov = qmp_output_visitor_new(); - /* FIXME: Empty visits are ugly, we should have a visit_type_null(). */ + visit_type_null(qmp_output_get_visitor(qov), NULL, &error_abort); obj = qmp_output_get_qobject(qov); g_assert(obj == &qnull_); qobject_decref(obj); qmp_output_visitor_cleanup(qov); + qmp_input_visitor_cleanup(qiv); g_assert(qnull_.refcnt == 1); } diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c index 80527eb..d06383a 100644 --- a/tests/test-qmp-input-visitor.c +++ b/tests/test-qmp-input-visitor.c @@ -279,6 +279,20 @@ static void test_visitor_in_any(TestInputVisitorData *data, qobject_decref(res); } +static void test_visitor_in_null(TestInputVisitorData *data, + const void *unused) +{ + Visitor *v; + + v = visitor_input_test_init(data, "null"); + visit_type_null(v, NULL, &error_abort); + + v = visitor_input_test_init(data, "{ 'a': null }"); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_null(v, "a", &error_abort); + visit_end_struct(v, &error_abort); +} + static void test_visitor_in_union_flat(TestInputVisitorData *data, const void *unused) { @@ -829,6 +843,8 @@ int main(int argc, char **argv) &in_visitor_data, test_visitor_in_list); input_visitor_test_add("/visitor/input/any", &in_visitor_data, test_visitor_in_any); + input_visitor_test_add("/visitor/input/null", + &in_visitor_data, test_visitor_in_null); input_visitor_test_add("/visitor/input/union-flat", &in_visitor_data, test_visitor_in_union_flat); input_visitor_test_add("/visitor/input/alternate", diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c index fddb5a6..e656d99 100644 --- a/tests/test-qmp-output-visitor.c +++ b/tests/test-qmp-output-visitor.c @@ -477,11 +477,12 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data, qobject_decref(arg); } -static void test_visitor_out_empty(TestOutputVisitorData *data, - const void *unused) +static void test_visitor_out_null(TestOutputVisitorData *data, + const void *unused) { QObject *arg; + visit_type_null(data->ov, NULL, &error_abort); arg = qmp_output_get_qobject(data->qov); g_assert(qobject_type(arg) == QTYPE_QNULL); qobject_decref(arg); @@ -837,8 +838,8 @@ int main(int argc, char **argv) &out_visitor_data, test_visitor_out_union_flat); output_visitor_test_add("/visitor/output/alternate", &out_visitor_data, test_visitor_out_alternate); - output_visitor_test_add("/visitor/output/empty", - &out_visitor_data, test_visitor_out_empty); + output_visitor_test_add("/visitor/output/null", + &out_visitor_data, test_visitor_out_null); output_visitor_test_add("/visitor/output/native_list/int", &out_visitor_data, test_visitor_out_native_list_int);