From patchwork Fri Nov 8 15:00:59 2019 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: 11235065 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9359313BD for ; Fri, 8 Nov 2019 15:06:19 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 67E18215EA for ; Fri, 8 Nov 2019 15:06:19 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="bOgk6x2+" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 67E18215EA Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:55896 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5q6-00079x-6b for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:06:18 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:45858) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5lo-0002jZ-BT for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:01:57 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5lm-0003Ku-TF for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:01:52 -0500 Received: from us-smtp-1.mimecast.com ([207.211.31.81]:39597 helo=us-smtp-delivery-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5lm-0003K3-PW for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:01:50 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225309; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=IKOvT4fY+hDgHdgpyHo2Rg2+75O/6kQXp/lWkffMxxI=; b=bOgk6x2+x0Ci3bnbDEtKgvOoY9hntGXk7a34w0k8u1Bl+2q9s9RRK/6vSEwRRwYsEIJ3kz +5/KV2y5VWVtTob5QfvLEtlh53bhuSQLCwEGLTM2F9+vJCvvxSZcizs6mEDDAanInbVfKD RM1M0ojp7iI1GAunyQHbwxwV+tBbIkQ= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-187-1fHarxj5MTSKzaWVESllyg-1; Fri, 08 Nov 2019 10:01:48 -0500 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id BAF101005502 for ; Fri, 8 Nov 2019 15:01:47 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4F98A5D6B7; Fri, 8 Nov 2019 15:01:39 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 01/25] qmp: constify QmpCommand and list Date: Fri, 8 Nov 2019 19:00:59 +0400 Message-Id: <20191108150123.12213-2-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-MC-Unique: 1fHarxj5MTSKzaWVESllyg-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 207.211.31.81 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" Since 0b69f6f72ce47a37a749b056b6d5ec64c61f11e8 "qapi: remove qmp_unregister_command()", the command list can be declared const. Signed-off-by: Marc-André Lureau Reviewed-by: Damien Hedde --- include/qapi/qmp/dispatch.h | 9 +++++---- monitor/misc.c | 2 +- monitor/monitor-internal.h | 2 +- qapi/qmp-dispatch.c | 6 +++--- qapi/qmp-registry.c | 6 +++--- qga/commands.c | 2 +- qga/main.c | 6 +++--- 7 files changed, 17 insertions(+), 16 deletions(-) diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h index 9aa426a398..5a9cf82472 100644 --- a/include/qapi/qmp/dispatch.h +++ b/include/qapi/qmp/dispatch.h @@ -39,7 +39,8 @@ typedef QTAILQ_HEAD(QmpCommandList, QmpCommand) QmpCommandList; void qmp_register_command(QmpCommandList *cmds, const char *name, QmpCommandFunc *fn, QmpCommandOptions options); -QmpCommand *qmp_find_command(QmpCommandList *cmds, const char *name); +const QmpCommand *qmp_find_command(const QmpCommandList *cmds, + const char *name); void qmp_disable_command(QmpCommandList *cmds, const char *name); void qmp_enable_command(QmpCommandList *cmds, const char *name); @@ -47,13 +48,13 @@ bool qmp_command_is_enabled(const QmpCommand *cmd); const char *qmp_command_name(const QmpCommand *cmd); bool qmp_has_success_response(const QmpCommand *cmd); QDict *qmp_error_response(Error *err); -QDict *qmp_dispatch(QmpCommandList *cmds, QObject *request, +QDict *qmp_dispatch(const QmpCommandList *cmds, QObject *request, bool allow_oob); bool qmp_is_oob(const QDict *dict); -typedef void (*qmp_cmd_callback_fn)(QmpCommand *cmd, void *opaque); +typedef void (*qmp_cmd_callback_fn)(const QmpCommand *cmd, void *opaque); -void qmp_for_each_command(QmpCommandList *cmds, qmp_cmd_callback_fn fn, +void qmp_for_each_command(const QmpCommandList *cmds, qmp_cmd_callback_fn fn, void *opaque); #endif diff --git a/monitor/misc.c b/monitor/misc.c index 3baa15f3bf..3052bfe8f1 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -230,7 +230,7 @@ static void hmp_info_help(Monitor *mon, const QDict *qdict) help_cmd(mon, "info"); } -static void query_commands_cb(QmpCommand *cmd, void *opaque) +static void query_commands_cb(const QmpCommand *cmd, void *opaque) { CommandInfoList *info, **list = opaque; diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h index d78f5ca190..3e7dac5910 100644 --- a/monitor/monitor-internal.h +++ b/monitor/monitor-internal.h @@ -132,7 +132,7 @@ typedef struct { * qmp_capabilities succeeds, we go into command mode, and * @command becomes &qmp_commands. */ - QmpCommandList *commands; + const QmpCommandList *commands; bool capab_offered[QMP_CAPABILITY__MAX]; /* capabilities offered */ bool capab[QMP_CAPABILITY__MAX]; /* offered and accepted */ /* diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index bc264b3c9b..857399c5fe 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -75,14 +75,14 @@ static QDict *qmp_dispatch_check_obj(const QObject *request, bool allow_oob, return dict; } -static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request, +static QObject *do_qmp_dispatch(const QmpCommandList *cmds, QObject *request, bool allow_oob, Error **errp) { Error *local_err = NULL; bool oob; const char *command; QDict *args, *dict; - QmpCommand *cmd; + const QmpCommand *cmd; QObject *ret = NULL; dict = qmp_dispatch_check_obj(request, allow_oob, errp); @@ -164,7 +164,7 @@ bool qmp_is_oob(const QDict *dict) && !qdict_haskey(dict, "execute"); } -QDict *qmp_dispatch(QmpCommandList *cmds, QObject *request, +QDict *qmp_dispatch(const QmpCommandList *cmds, QObject *request, bool allow_oob) { Error *err = NULL; diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c index ca00f74795..d0f9a1d3e3 100644 --- a/qapi/qmp-registry.c +++ b/qapi/qmp-registry.c @@ -27,7 +27,7 @@ void qmp_register_command(QmpCommandList *cmds, const char *name, QTAILQ_INSERT_TAIL(cmds, cmd, node); } -QmpCommand *qmp_find_command(QmpCommandList *cmds, const char *name) +const QmpCommand *qmp_find_command(const QmpCommandList *cmds, const char *name) { QmpCommand *cmd; @@ -77,10 +77,10 @@ bool qmp_has_success_response(const QmpCommand *cmd) return !(cmd->options & QCO_NO_SUCCESS_RESP); } -void qmp_for_each_command(QmpCommandList *cmds, qmp_cmd_callback_fn fn, +void qmp_for_each_command(const QmpCommandList *cmds, qmp_cmd_callback_fn fn, void *opaque) { - QmpCommand *cmd; + const QmpCommand *cmd; QTAILQ_FOREACH(cmd, cmds, node) { fn(cmd, opaque); diff --git a/qga/commands.c b/qga/commands.c index 0c7d1385c2..05e9ab6c3d 100644 --- a/qga/commands.c +++ b/qga/commands.c @@ -54,7 +54,7 @@ void qmp_guest_ping(Error **errp) slog("guest-ping called"); } -static void qmp_command_info(QmpCommand *cmd, void *opaque) +static void qmp_command_info(const QmpCommand *cmd, void *opaque) { GuestAgentInfo *info = opaque; GuestAgentCommandInfo *cmd_info; diff --git a/qga/main.c b/qga/main.c index c35c2a2120..f23614528e 100644 --- a/qga/main.c +++ b/qga/main.c @@ -359,7 +359,7 @@ static gint ga_strcmp(gconstpointer str1, gconstpointer str2) } /* disable commands that aren't safe for fsfreeze */ -static void ga_disable_non_whitelisted(QmpCommand *cmd, void *opaque) +static void ga_disable_non_whitelisted(const QmpCommand *cmd, void *opaque) { bool whitelisted = false; int i = 0; @@ -378,7 +378,7 @@ static void ga_disable_non_whitelisted(QmpCommand *cmd, void *opaque) } /* [re-]enable all commands, except those explicitly blacklisted by user */ -static void ga_enable_non_blacklisted(QmpCommand *cmd, void *opaque) +static void ga_enable_non_blacklisted(const QmpCommand *cmd, void *opaque) { GList *blacklist = opaque; const char *name = qmp_command_name(cmd); @@ -918,7 +918,7 @@ int64_t ga_get_fd_handle(GAState *s, Error **errp) return handle; } -static void ga_print_cmd(QmpCommand *cmd, void *opaque) +static void ga_print_cmd(const QmpCommand *cmd, void *opaque) { printf("%s\n", qmp_command_name(cmd)); } From patchwork Fri Nov 8 15:01:00 2019 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: 11235061 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 357951747 for ; Fri, 8 Nov 2019 15:04:59 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 05BE7215EA for ; Fri, 8 Nov 2019 15:04:59 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="DtR8vfgg" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 05BE7215EA Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:55870 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5on-00058W-Im for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:04:57 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:45904) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5m4-0002oe-Cc for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:02:09 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5m3-0003U3-9h for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:02:08 -0500 Received: from us-smtp-delivery-1.mimecast.com ([207.211.31.120]:35638 helo=us-smtp-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5m1-0003Sr-Ld for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:02:05 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225323; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=idH6Lctnz6gUEPfhrh3e0GxtIlG3tIR/wVTbHh5fUtY=; b=DtR8vfggYqpU+Sss7X2J5hWPR8o6gv4u+RWSAkrpYdIl9dJh1QNyfibfZfSx12EFYLEEqN m43NczBnrSTwRxl8OaG0I+YaqlhWRCUpctXPY0YREX9g9e7men0OzArHeO6tn2/FgcLUnK AmFp4mlRGRUeHhG+z/whmDTf/GmbTjc= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-83-LoBFHHMCMXGgzrwgXXSpFA-1; Fri, 08 Nov 2019 10:02:00 -0500 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 10117477 for ; Fri, 8 Nov 2019 15:02:00 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0DC5160C18; Fri, 8 Nov 2019 15:01:52 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 02/25] json-lexer: make it safe to call destroy multiple times Date: Fri, 8 Nov 2019 19:01:00 +0400 Message-Id: <20191108150123.12213-3-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-MC-Unique: LoBFHHMCMXGgzrwgXXSpFA-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 207.211.31.120 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" We can easily avoid the burden of checking if the lexer was initialized prior to calling destroy by the caller, let's do it. This allows simplification in state tracking with the following patch, "qmp: add QmpSession" can call qmp_session_destroy() multiple times, which in turns calls json_lexer_destroy(). Signed-off-by: Marc-André Lureau Reviewed-by: Damien Hedde --- qobject/json-lexer.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/qobject/json-lexer.c b/qobject/json-lexer.c index 632320d72d..fa7a2c43a8 100644 --- a/qobject/json-lexer.c +++ b/qobject/json-lexer.c @@ -361,5 +361,8 @@ void json_lexer_flush(JSONLexer *lexer) void json_lexer_destroy(JSONLexer *lexer) { - g_string_free(lexer->token, true); + if (lexer->token) { + g_string_free(lexer->token, true); + lexer->token = NULL; + } } From patchwork Fri Nov 8 15:01:01 2019 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: 11235073 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D0C321390 for ; Fri, 8 Nov 2019 15:08:54 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 97AFB215EA for ; Fri, 8 Nov 2019 15:08:54 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="HQY/xJ+2" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 97AFB215EA Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:55934 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5sb-0002VN-El for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:08:53 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:45979) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5mG-0002wP-IV for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:02:26 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5mE-0003Za-ID for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:02:20 -0500 Received: from us-smtp-delivery-1.mimecast.com ([205.139.110.120]:39309 helo=us-smtp-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5mE-0003ZJ-DS for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:02:18 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225338; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=NDyzyp9lszBVzhOgIQ8TOZ58QA1kDkQfY7FbGxmBrS0=; b=HQY/xJ+26apn4ZTKVIW6xCijrCS8cg78HN16RagXo1By7hF+d48290COPNidOw6NdVPDdY k5Hot2k6yz1drcNoasz1br4PnTmqhUMbFA+SLedm41PfhNYNWl5TV9MUVB4uemYyGVOoTW kdFOkTiPT+PD7EGg/5+VIXShDwHsHMw= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-346-u12A6TUTMCqvp7LGicK1aQ-1; Fri, 08 Nov 2019 10:02:16 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id B0056180496F for ; Fri, 8 Nov 2019 15:02:15 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 6F5296084E; Fri, 8 Nov 2019 15:02:05 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 03/25] qmp: add QmpSession Date: Fri, 8 Nov 2019 19:01:01 +0400 Message-Id: <20191108150123.12213-4-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-MC-Unique: u12A6TUTMCqvp7LGicK1aQ-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 205.139.110.120 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" This structure will hold various data related to a QMP client session: the list of commands, the parser, the callbacks, the pending operations... Signed-off-by: Marc-André Lureau --- include/qapi/qmp/dispatch.h | 10 +++++++++- monitor/misc.c | 6 +++--- monitor/monitor-internal.h | 2 +- monitor/monitor.c | 2 +- monitor/qmp.c | 8 +++++--- qapi/qmp-dispatch.c | 15 ++++++++++++--- qga/main.c | 5 ++++- tests/test-qmp-cmds.c | 28 ++++++++++++++++++++++------ 8 files changed, 57 insertions(+), 19 deletions(-) diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h index 5a9cf82472..3b53cfd788 100644 --- a/include/qapi/qmp/dispatch.h +++ b/include/qapi/qmp/dispatch.h @@ -37,10 +37,18 @@ typedef struct QmpCommand typedef QTAILQ_HEAD(QmpCommandList, QmpCommand) QmpCommandList; +typedef struct QmpSession QmpSession; + +struct QmpSession { + const QmpCommandList *cmds; +}; + void qmp_register_command(QmpCommandList *cmds, const char *name, QmpCommandFunc *fn, QmpCommandOptions options); const QmpCommand *qmp_find_command(const QmpCommandList *cmds, const char *name); +void qmp_session_init(QmpSession *session, const QmpCommandList *cmds); +void qmp_session_destroy(QmpSession *session); void qmp_disable_command(QmpCommandList *cmds, const char *name); void qmp_enable_command(QmpCommandList *cmds, const char *name); @@ -48,7 +56,7 @@ bool qmp_command_is_enabled(const QmpCommand *cmd); const char *qmp_command_name(const QmpCommand *cmd); bool qmp_has_success_response(const QmpCommand *cmd); QDict *qmp_error_response(Error *err); -QDict *qmp_dispatch(const QmpCommandList *cmds, QObject *request, +QDict *qmp_dispatch(QmpSession *session, QObject *request, bool allow_oob); bool qmp_is_oob(const QDict *dict); diff --git a/monitor/misc.c b/monitor/misc.c index 3052bfe8f1..bb33ca73cf 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -253,7 +253,7 @@ CommandInfoList *qmp_query_commands(Error **errp) assert(monitor_is_qmp(cur_mon)); mon = container_of(cur_mon, MonitorQMP, common); - qmp_for_each_command(mon->commands, query_commands_cb, &list); + qmp_for_each_command(mon->session.cmds, query_commands_cb, &list); return list; } @@ -363,7 +363,7 @@ void qmp_qmp_capabilities(bool has_enable, QMPCapabilityList *enable, assert(monitor_is_qmp(cur_mon)); mon = container_of(cur_mon, MonitorQMP, common); - if (mon->commands == &qmp_commands) { + if (mon->session.cmds == &qmp_commands) { error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND, "Capabilities negotiation is already complete, command " "ignored"); @@ -374,7 +374,7 @@ void qmp_qmp_capabilities(bool has_enable, QMPCapabilityList *enable, return; } - mon->commands = &qmp_commands; + mon->session.cmds = &qmp_commands; } /* Set the current CPU defined by the user. Callers must hold BQL. */ diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h index 3e7dac5910..b15266e77b 100644 --- a/monitor/monitor-internal.h +++ b/monitor/monitor-internal.h @@ -132,7 +132,7 @@ typedef struct { * qmp_capabilities succeeds, we go into command mode, and * @command becomes &qmp_commands. */ - const QmpCommandList *commands; + QmpSession session; bool capab_offered[QMP_CAPABILITY__MAX]; /* capabilities offered */ bool capab[QMP_CAPABILITY__MAX]; /* offered and accepted */ /* diff --git a/monitor/monitor.c b/monitor/monitor.c index 12898b6448..ecf21d9786 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -263,7 +263,7 @@ static void monitor_qapi_event_emit(QAPIEvent event, QDict *qdict) } qmp_mon = container_of(mon, MonitorQMP, common); - if (qmp_mon->commands != &qmp_cap_negotiation_commands) { + if (qmp_mon->session.cmds != &qmp_cap_negotiation_commands) { qmp_send_response(qmp_mon, qdict); } } diff --git a/monitor/qmp.c b/monitor/qmp.c index 9d9e5d8b27..24ccdeb4a4 100644 --- a/monitor/qmp.c +++ b/monitor/qmp.c @@ -117,11 +117,11 @@ static void monitor_qmp_dispatch(MonitorQMP *mon, QObject *req) old_mon = cur_mon; cur_mon = &mon->common; - rsp = qmp_dispatch(mon->commands, req, qmp_oob_enabled(mon)); + rsp = qmp_dispatch(&mon->session, req, qmp_oob_enabled(mon)); cur_mon = old_mon; - if (mon->commands == &qmp_cap_negotiation_commands) { + if (mon->session.cmds == &qmp_cap_negotiation_commands) { error = qdict_get_qdict(rsp, "error"); if (error && !g_strcmp0(qdict_get_try_str(error, "class"), @@ -318,7 +318,7 @@ static void monitor_qmp_event(void *opaque, int event) switch (event) { case CHR_EVENT_OPENED: - mon->commands = &qmp_cap_negotiation_commands; + qmp_session_init(&mon->session, &qmp_cap_negotiation_commands); monitor_qmp_caps_reset(mon); data = qmp_greeting(mon); qmp_send_response(mon, data); @@ -333,6 +333,7 @@ static void monitor_qmp_event(void *opaque, int event) * is closed. */ monitor_qmp_cleanup_queues(mon); + qmp_session_destroy(&mon->session); json_message_parser_destroy(&mon->parser); json_message_parser_init(&mon->parser, handle_qmp_command, mon, NULL); @@ -344,6 +345,7 @@ static void monitor_qmp_event(void *opaque, int event) void monitor_data_destroy_qmp(MonitorQMP *mon) { + qmp_session_destroy(&mon->session); json_message_parser_destroy(&mon->parser); qemu_mutex_destroy(&mon->qmp_queue_lock); monitor_qmp_cleanup_req_queue_locked(mon); diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index 857399c5fe..0e6b003dd8 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -164,15 +164,24 @@ bool qmp_is_oob(const QDict *dict) && !qdict_haskey(dict, "execute"); } -QDict *qmp_dispatch(const QmpCommandList *cmds, QObject *request, - bool allow_oob) +void qmp_session_init(QmpSession *session, const QmpCommandList *cmds) +{ + session->cmds = cmds; +} + +void qmp_session_destroy(QmpSession *session) +{ + session->cmds = NULL; +} + +QDict *qmp_dispatch(QmpSession *session, QObject *request, bool allow_oob) { Error *err = NULL; QDict *dict = qobject_to(QDict, request); QObject *ret, *id = dict ? qdict_get(dict, "id") : NULL; QDict *rsp; - ret = do_qmp_dispatch(cmds, request, allow_oob, &err); + ret = do_qmp_dispatch(session->cmds, request, allow_oob, &err); if (err) { rsp = qmp_error_response(err); } else if (ret) { diff --git a/qga/main.c b/qga/main.c index f23614528e..61190db5f3 100644 --- a/qga/main.c +++ b/qga/main.c @@ -74,6 +74,7 @@ typedef struct GAPersistentState { typedef struct GAConfig GAConfig; struct GAState { + QmpSession session; JSONMessageParser parser; GMainLoop *main_loop; GAChannel *channel; @@ -572,7 +573,7 @@ static void process_event(void *opaque, QObject *obj, Error *err) } g_debug("processing command"); - rsp = qmp_dispatch(&ga_commands, obj, false); + rsp = qmp_dispatch(&s->session, obj, false); end: ret = send_response(s, rsp); @@ -1338,6 +1339,7 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation) ga_command_state_init(s, s->command_state); ga_command_state_init_all(s->command_state); json_message_parser_init(&s->parser, process_event, s, NULL); + qmp_session_init(&s->session, &ga_commands); #ifndef _WIN32 if (!register_signal_handlers()) { @@ -1369,6 +1371,7 @@ static void cleanup_agent(GAState *s) CloseHandle(s->wakeup_event); #endif if (s->command_state) { + qmp_session_destroy(&s->session); ga_command_state_cleanup_all(s->command_state); ga_command_state_free(s->command_state); json_message_parser_destroy(&s->parser); diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c index 27b0afe55a..962c2cb2e1 100644 --- a/tests/test-qmp-cmds.c +++ b/tests/test-qmp-cmds.c @@ -147,44 +147,52 @@ __org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a, /* test commands with no input and no return value */ static void test_dispatch_cmd(void) { + QmpSession session = { 0, }; QDict *req = qdict_new(); QDict *resp; + qmp_session_init(&session, &qmp_commands); qdict_put_str(req, "execute", "user_def_cmd"); - resp = qmp_dispatch(&qmp_commands, QOBJECT(req), false); + resp = qmp_dispatch(&session, QOBJECT(req), false); assert(resp != NULL); assert(!qdict_haskey(resp, "error")); qobject_unref(resp); qobject_unref(req); + qmp_session_destroy(&session); } static void test_dispatch_cmd_oob(void) { + QmpSession session = { 0, }; QDict *req = qdict_new(); QDict *resp; + qmp_session_init(&session, &qmp_commands); qdict_put_str(req, "exec-oob", "test-flags-command"); - resp = qmp_dispatch(&qmp_commands, QOBJECT(req), true); + resp = qmp_dispatch(&session, QOBJECT(req), true); assert(resp != NULL); assert(!qdict_haskey(resp, "error")); qobject_unref(resp); qobject_unref(req); + qmp_session_destroy(&session); } /* test commands that return an error due to invalid parameters */ static void test_dispatch_cmd_failure(void) { + QmpSession session = { 0, }; QDict *req = qdict_new(); QDict *args = qdict_new(); QDict *resp; + qmp_session_init(&session, &qmp_commands); qdict_put_str(req, "execute", "user_def_cmd2"); - resp = qmp_dispatch(&qmp_commands, QOBJECT(req), false); + resp = qmp_dispatch(&session, QOBJECT(req), false); assert(resp != NULL); assert(qdict_haskey(resp, "error")); @@ -198,36 +206,44 @@ static void test_dispatch_cmd_failure(void) qdict_put_str(req, "execute", "user_def_cmd"); - resp = qmp_dispatch(&qmp_commands, QOBJECT(req), false); + resp = qmp_dispatch(&session, QOBJECT(req), false); assert(resp != NULL); assert(qdict_haskey(resp, "error")); qobject_unref(resp); qobject_unref(req); + qmp_session_destroy(&session); } static void test_dispatch_cmd_success_response(void) { + QmpSession session = { 0, }; QDict *req = qdict_new(); QDict *resp; + qmp_session_init(&session, &qmp_commands); qdict_put_str(req, "execute", "cmd-success-response"); - resp = qmp_dispatch(&qmp_commands, QOBJECT(req), false); + resp = qmp_dispatch(&session, QOBJECT(req), false); g_assert_null(resp); qobject_unref(req); + qmp_session_destroy(&session); } + static QObject *test_qmp_dispatch(QDict *req) { + QmpSession session = { 0, }; QDict *resp; QObject *ret; - resp = qmp_dispatch(&qmp_commands, QOBJECT(req), false); + qmp_session_init(&session, &qmp_commands); + resp = qmp_dispatch(&session, QOBJECT(req), false); assert(resp && !qdict_haskey(resp, "error")); ret = qdict_get(resp, "return"); assert(ret); qobject_ref(ret); qobject_unref(resp); + qmp_session_destroy(&session); return ret; } From patchwork Fri Nov 8 15:01:02 2019 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: 11235069 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 733E113BD for ; Fri, 8 Nov 2019 15:07:47 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 38D5B215EA for ; Fri, 8 Nov 2019 15:07:47 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="J8P6mAMQ" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 38D5B215EA Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:55918 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5rV-0000WB-O3 for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:07:45 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:46145) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5mV-00036Y-6F for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:02:36 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5mT-0003jd-8p for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:02:35 -0500 Received: from us-smtp-1.mimecast.com ([207.211.31.81]:42287 helo=us-smtp-delivery-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5mS-0003in-PL for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:02:33 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225351; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=l8Z5y8d3WkdwB1zLwwtTktsfJb3xTBuj4vDuH+BQs3M=; b=J8P6mAMQlZzICfoRrxIu3skZiXRoRpazJ49moWwo3gmIjtEy17jVyNEFR0hGNDfQcFJ1pw tfYCIrlH3XQw8C35zeBj3xscxGFtbGr6KcOnoaemmjOS02/da0oOapu5WprEjR6bMSFWmP YW9MI85WbD2h5a4vbF04LsWPDw2w5AA= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-393-Q7UhsJ4SNl24DoQYGMwVnw-1; Fri, 08 Nov 2019 10:02:29 -0500 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 1D4C3800C72 for ; Fri, 8 Nov 2019 15:02:29 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 54F7A600C9; Fri, 8 Nov 2019 15:02:20 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 04/25] QmpSession: add a return callback Date: Fri, 8 Nov 2019 19:01:02 +0400 Message-Id: <20191108150123.12213-5-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-MC-Unique: Q7UhsJ4SNl24DoQYGMwVnw-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 207.211.31.81 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" Introduce a return_cb to allow delaying finishing the dispatch and sending the response asynchronously. For now, this is just modifying qmp_dispatch() to call the callback synchronously. Signed-off-by: Marc-André Lureau --- include/qapi/qmp/dispatch.h | 10 ++++-- monitor/qmp.c | 47 ++++++++++--------------- qapi/qmp-dispatch.c | 22 +++++++++--- qga/main.c | 34 +++++++++++------- tests/test-qmp-cmds.c | 69 ++++++++++++++++++------------------- 5 files changed, 98 insertions(+), 84 deletions(-) diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h index 3b53cfd788..d1ce631a93 100644 --- a/include/qapi/qmp/dispatch.h +++ b/include/qapi/qmp/dispatch.h @@ -38,16 +38,20 @@ typedef struct QmpCommand typedef QTAILQ_HEAD(QmpCommandList, QmpCommand) QmpCommandList; typedef struct QmpSession QmpSession; +typedef void (QmpDispatchReturn) (QmpSession *session, QDict *rsp); struct QmpSession { const QmpCommandList *cmds; + QmpDispatchReturn *return_cb; }; void qmp_register_command(QmpCommandList *cmds, const char *name, QmpCommandFunc *fn, QmpCommandOptions options); const QmpCommand *qmp_find_command(const QmpCommandList *cmds, const char *name); -void qmp_session_init(QmpSession *session, const QmpCommandList *cmds); +void qmp_session_init(QmpSession *session, + const QmpCommandList *cmds, + QmpDispatchReturn *return_cb); void qmp_session_destroy(QmpSession *session); void qmp_disable_command(QmpCommandList *cmds, const char *name); void qmp_enable_command(QmpCommandList *cmds, const char *name); @@ -56,8 +60,8 @@ bool qmp_command_is_enabled(const QmpCommand *cmd); const char *qmp_command_name(const QmpCommand *cmd); bool qmp_has_success_response(const QmpCommand *cmd); QDict *qmp_error_response(Error *err); -QDict *qmp_dispatch(QmpSession *session, QObject *request, - bool allow_oob); +void qmp_dispatch(QmpSession *session, QObject *request, + bool allow_oob); bool qmp_is_oob(const QDict *dict); typedef void (*qmp_cmd_callback_fn)(const QmpCommand *cmd, void *opaque); diff --git a/monitor/qmp.c b/monitor/qmp.c index 24ccdeb4a4..b215cb70f3 100644 --- a/monitor/qmp.c +++ b/monitor/qmp.c @@ -96,45 +96,35 @@ void qmp_send_response(MonitorQMP *mon, const QDict *rsp) qobject_unref(json); } -/* - * Emit QMP response @rsp to @mon. - * Null @rsp can only happen for commands with QCO_NO_SUCCESS_RESP. - * Nothing is emitted then. - */ -static void monitor_qmp_respond(MonitorQMP *mon, QDict *rsp) +static void dispatch_return_cb(QmpSession *session, QDict *rsp) { - if (rsp) { - qmp_send_response(mon, rsp); + MonitorQMP *mon = container_of(session, MonitorQMP, session); + + if (mon->session.cmds == &qmp_cap_negotiation_commands) { + QDict *error = qdict_get_qdict(rsp, "error"); + if (error + && !g_strcmp0(qdict_get_try_str(error, "class"), + QapiErrorClass_str(ERROR_CLASS_COMMAND_NOT_FOUND))) { + /* Provide a more useful error message */ + qdict_del(error, "desc"); + qdict_put_str(error, "desc", "Expecting capabilities negotiation" + " with 'qmp_capabilities'"); + } } + + qmp_send_response(mon, rsp); } static void monitor_qmp_dispatch(MonitorQMP *mon, QObject *req) { Monitor *old_mon; - QDict *rsp; - QDict *error; old_mon = cur_mon; cur_mon = &mon->common; - rsp = qmp_dispatch(&mon->session, req, qmp_oob_enabled(mon)); + qmp_dispatch(&mon->session, req, qmp_oob_enabled(mon)); cur_mon = old_mon; - - if (mon->session.cmds == &qmp_cap_negotiation_commands) { - error = qdict_get_qdict(rsp, "error"); - if (error - && !g_strcmp0(qdict_get_try_str(error, "class"), - QapiErrorClass_str(ERROR_CLASS_COMMAND_NOT_FOUND))) { - /* Provide a more useful error message */ - qdict_del(error, "desc"); - qdict_put_str(error, "desc", "Expecting capabilities negotiation" - " with 'qmp_capabilities'"); - } - } - - monitor_qmp_respond(mon, rsp); - qobject_unref(rsp); } /* @@ -211,7 +201,7 @@ void monitor_qmp_bh_dispatcher(void *data) assert(req_obj->err); rsp = qmp_error_response(req_obj->err); req_obj->err = NULL; - monitor_qmp_respond(mon, rsp); + qmp_send_response(req_obj->mon, rsp); qobject_unref(rsp); } @@ -318,7 +308,8 @@ static void monitor_qmp_event(void *opaque, int event) switch (event) { case CHR_EVENT_OPENED: - qmp_session_init(&mon->session, &qmp_cap_negotiation_commands); + qmp_session_init(&mon->session, + &qmp_cap_negotiation_commands, dispatch_return_cb); monitor_qmp_caps_reset(mon); data = qmp_greeting(mon); qmp_send_response(mon, data); diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index 0e6b003dd8..1314f4929f 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -164,17 +164,28 @@ bool qmp_is_oob(const QDict *dict) && !qdict_haskey(dict, "execute"); } -void qmp_session_init(QmpSession *session, const QmpCommandList *cmds) +void qmp_session_init(QmpSession *session, + const QmpCommandList *cmds, + QmpDispatchReturn *return_cb) { + assert(return_cb); + assert(!session->return_cb); + session->cmds = cmds; + session->return_cb = return_cb; } void qmp_session_destroy(QmpSession *session) { + if (!session->return_cb) { + return; + } + session->cmds = NULL; + session->return_cb = NULL; } -QDict *qmp_dispatch(QmpSession *session, QObject *request, bool allow_oob) +void qmp_dispatch(QmpSession *session, QObject *request, bool allow_oob) { Error *err = NULL; QDict *dict = qobject_to(QDict, request); @@ -189,12 +200,13 @@ QDict *qmp_dispatch(QmpSession *session, QObject *request, bool allow_oob) qdict_put_obj(rsp, "return", ret); } else { /* Can only happen for commands with QCO_NO_SUCCESS_RESP */ - rsp = NULL; + return; } - if (rsp && id) { + if (id) { qdict_put_obj(rsp, "id", qobject_ref(id)); } - return rsp; + session->return_cb(session, rsp); + qobject_unref(rsp); } diff --git a/qga/main.c b/qga/main.c index 61190db5f3..c291d06491 100644 --- a/qga/main.c +++ b/qga/main.c @@ -558,29 +558,37 @@ static int send_response(GAState *s, const QDict *rsp) return 0; } +static void dispatch_return_cb(QmpSession *session, QDict *rsp) +{ + GAState *s = container_of(session, GAState, session); + int ret = send_response(s, rsp); + if (ret < 0) { + g_warning("error sending response: %s", strerror(-ret)); + } +} + /* handle requests/control events coming in over the channel */ static void process_event(void *opaque, QObject *obj, Error *err) { GAState *s = opaque; - QDict *rsp; int ret; g_debug("process_event: called"); assert(!obj != !err); - if (err) { - rsp = qmp_error_response(err); - goto end; - } - g_debug("processing command"); - rsp = qmp_dispatch(&s->session, obj, false); + if (err) { + QDict *rsp = qmp_error_response(err); -end: - ret = send_response(s, rsp); - if (ret < 0) { - g_warning("error sending error response: %s", strerror(-ret)); + ret = send_response(s, rsp); + if (ret < 0) { + g_warning("error sending error response: %s", strerror(-ret)); + } + qobject_unref(rsp); + } else { + g_debug("processing command"); + qmp_dispatch(&s->session, obj, false); } - qobject_unref(rsp); + qobject_unref(obj); } @@ -1339,7 +1347,7 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation) ga_command_state_init(s, s->command_state); ga_command_state_init_all(s->command_state); json_message_parser_init(&s->parser, process_event, s, NULL); - qmp_session_init(&s->session, &ga_commands); + qmp_session_init(&s->session, &ga_commands, dispatch_return_cb); #ifndef _WIN32 if (!register_signal_handlers()) { diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c index 962c2cb2e1..cca15e79ba 100644 --- a/tests/test-qmp-cmds.c +++ b/tests/test-qmp-cmds.c @@ -143,22 +143,23 @@ __org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a, return ret; } +static void dispatch_cmd_return(QmpSession *session, QDict *resp) +{ + assert(resp != NULL); + assert(!qdict_haskey(resp, "error")); +} /* test commands with no input and no return value */ static void test_dispatch_cmd(void) { QmpSession session = { 0, }; QDict *req = qdict_new(); - QDict *resp; - qmp_session_init(&session, &qmp_commands); + qmp_session_init(&session, &qmp_commands, dispatch_cmd_return); qdict_put_str(req, "execute", "user_def_cmd"); - resp = qmp_dispatch(&session, QOBJECT(req), false); - assert(resp != NULL); - assert(!qdict_haskey(resp, "error")); + qmp_dispatch(&session, QOBJECT(req), false); - qobject_unref(resp); qobject_unref(req); qmp_session_destroy(&session); } @@ -167,82 +168,80 @@ static void test_dispatch_cmd_oob(void) { QmpSession session = { 0, }; QDict *req = qdict_new(); - QDict *resp; - qmp_session_init(&session, &qmp_commands); + qmp_session_init(&session, &qmp_commands, dispatch_cmd_return); qdict_put_str(req, "exec-oob", "test-flags-command"); - resp = qmp_dispatch(&session, QOBJECT(req), true); - assert(resp != NULL); - assert(!qdict_haskey(resp, "error")); + qmp_dispatch(&session, QOBJECT(req), true); - qobject_unref(resp); qobject_unref(req); qmp_session_destroy(&session); } +static void dispatch_cmd_failure_return(QmpSession *session, QDict *resp) +{ + assert(resp != NULL); + assert(qdict_haskey(resp, "error")); +} + /* test commands that return an error due to invalid parameters */ static void test_dispatch_cmd_failure(void) { QmpSession session = { 0, }; QDict *req = qdict_new(); QDict *args = qdict_new(); - QDict *resp; - qmp_session_init(&session, &qmp_commands); + qmp_session_init(&session, &qmp_commands, dispatch_cmd_failure_return); qdict_put_str(req, "execute", "user_def_cmd2"); - resp = qmp_dispatch(&session, QOBJECT(req), false); - assert(resp != NULL); - assert(qdict_haskey(resp, "error")); + qmp_dispatch(&session, QOBJECT(req), false); - qobject_unref(resp); qobject_unref(req); /* check that with extra arguments it throws an error */ req = qdict_new(); qdict_put_int(args, "a", 66); qdict_put(req, "arguments", args); - qdict_put_str(req, "execute", "user_def_cmd"); - resp = qmp_dispatch(&session, QOBJECT(req), false); - assert(resp != NULL); - assert(qdict_haskey(resp, "error")); + qmp_dispatch(&session, QOBJECT(req), false); - qobject_unref(resp); qobject_unref(req); qmp_session_destroy(&session); } +static QObject *dispatch_ret; + static void test_dispatch_cmd_success_response(void) { QmpSession session = { 0, }; QDict *req = qdict_new(); - QDict *resp; - qmp_session_init(&session, &qmp_commands); + qmp_session_init(&session, &qmp_commands, (QmpDispatchReturn *)abort); qdict_put_str(req, "execute", "cmd-success-response"); - resp = qmp_dispatch(&session, QOBJECT(req), false); - g_assert_null(resp); + + qmp_dispatch(&session, QOBJECT(req), false); + qobject_unref(req); qmp_session_destroy(&session); } +static void dispatch_return(QmpSession *session, QDict *resp) +{ + assert(resp && !qdict_haskey(resp, "error")); + dispatch_ret = qdict_get(resp, "return"); + qobject_ref(dispatch_ret); +} static QObject *test_qmp_dispatch(QDict *req) { QmpSession session = { 0, }; - QDict *resp; QObject *ret; - qmp_session_init(&session, &qmp_commands); - resp = qmp_dispatch(&session, QOBJECT(req), false); - assert(resp && !qdict_haskey(resp, "error")); - ret = qdict_get(resp, "return"); - assert(ret); - qobject_ref(ret); - qobject_unref(resp); + qmp_session_init(&session, &qmp_commands, dispatch_return); + qmp_dispatch(&session, QOBJECT(req), false); + ret = dispatch_ret; + dispatch_ret = NULL; qmp_session_destroy(&session); return ret; } From patchwork Fri Nov 8 15:01:03 2019 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: 11235067 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 685F51390 for ; Fri, 8 Nov 2019 15:06:40 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 3F7C0215EA for ; Fri, 8 Nov 2019 15:06:40 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="MXIiUya/" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 3F7C0215EA Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:55908 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5qR-0007lL-3B for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:06:39 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:46171) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5mj-0003Cd-DL for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:02:50 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5mi-0003o2-1I for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:02:49 -0500 Received: from us-smtp-1.mimecast.com ([207.211.31.81]:49936 helo=us-smtp-delivery-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5mg-0003nG-2v for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:02:46 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225364; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=e1yDkbX9kSrQE2esR1pQgQNkZhwENHxRrNgX62Wk9qo=; b=MXIiUya/MPD2Ez2ZMO3WRgSUVGJrGMj9oeAV2dc1fDGh2U6QlROkmBsw3yScmtxyc0HrDx jEy6MP1v17zsv4YMPll0Z9RWLcAW8Ddt5FyoXL3NqKkIX6ae2lCeyoCb9fhlvMmJxDyP/A EHaR0pusZ/Z35NiNuk/9v4WQnnU206I= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-283-LzGJj93WOm6s5V5vro0rcg-1; Fri, 08 Nov 2019 10:02:43 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id CF4778017DD for ; Fri, 8 Nov 2019 15:02:42 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 202A65C1BB; Fri, 8 Nov 2019 15:02:34 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 05/25] QmpSession: add json parser and use it in qga Date: Fri, 8 Nov 2019 19:01:03 +0400 Message-Id: <20191108150123.12213-6-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-MC-Unique: LzGJj93WOm6s5V5vro0rcg-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 207.211.31.81 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" Move JSON parser to QmpSession, and implement a simple handler to check the parsed tokens and call qmp_dispatch(). This is enough for a simple QMP client, like QGA. The QEMU monitor has more complicated handling of dispatching which will be addressed in a following patch to benefit from more common code. Signed-off-by: Marc-André Lureau --- include/qapi/qmp/dispatch.h | 7 +++++++ qapi/qmp-dispatch.c | 19 +++++++++++++++++++ qga/main.c | 31 +------------------------------ 3 files changed, 27 insertions(+), 30 deletions(-) diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h index d1ce631a93..c84edff7d2 100644 --- a/include/qapi/qmp/dispatch.h +++ b/include/qapi/qmp/dispatch.h @@ -15,6 +15,7 @@ #define QAPI_QMP_DISPATCH_H #include "qemu/queue.h" +#include "qapi/qmp/json-parser.h" typedef void (QmpCommandFunc)(QDict *, QObject **, Error **); @@ -42,6 +43,7 @@ typedef void (QmpDispatchReturn) (QmpSession *session, QDict *rsp); struct QmpSession { const QmpCommandList *cmds; + JSONMessageParser parser; QmpDispatchReturn *return_cb; }; @@ -52,6 +54,11 @@ const QmpCommand *qmp_find_command(const QmpCommandList *cmds, void qmp_session_init(QmpSession *session, const QmpCommandList *cmds, QmpDispatchReturn *return_cb); +static inline void +qmp_session_feed(QmpSession *session, const char *buf, size_t count) +{ + json_message_parser_feed(&session->parser, buf, count); +} void qmp_session_destroy(QmpSession *session); void qmp_disable_command(QmpCommandList *cmds, const char *name); void qmp_enable_command(QmpCommandList *cmds, const char *name); diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index 1314f4929f..f8c491924d 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -164,6 +164,23 @@ bool qmp_is_oob(const QDict *dict) && !qdict_haskey(dict, "execute"); } +static void qmp_json_emit(void *opaque, QObject *obj, Error *err) +{ + QmpSession *session = opaque; + + assert(!obj != !err); + + if (err) { + QDict *rsp = qmp_error_response(err); + session->return_cb(session, rsp); + qobject_unref(rsp); + } else { + qmp_dispatch(session, obj, false); + } + + qobject_unref(obj); +} + void qmp_session_init(QmpSession *session, const QmpCommandList *cmds, QmpDispatchReturn *return_cb) @@ -171,6 +188,7 @@ void qmp_session_init(QmpSession *session, assert(return_cb); assert(!session->return_cb); + json_message_parser_init(&session->parser, qmp_json_emit, session, NULL); session->cmds = cmds; session->return_cb = return_cb; } @@ -183,6 +201,7 @@ void qmp_session_destroy(QmpSession *session) session->cmds = NULL; session->return_cb = NULL; + json_message_parser_destroy(&session->parser); } void qmp_dispatch(QmpSession *session, QObject *request, bool allow_oob) diff --git a/qga/main.c b/qga/main.c index c291d06491..057368eb16 100644 --- a/qga/main.c +++ b/qga/main.c @@ -19,7 +19,6 @@ #include #endif #include "qemu-common.h" -#include "qapi/qmp/json-parser.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qjson.h" #include "qapi/qmp/qstring.h" @@ -75,7 +74,6 @@ typedef struct GAConfig GAConfig; struct GAState { QmpSession session; - JSONMessageParser parser; GMainLoop *main_loop; GAChannel *channel; bool virtio; /* fastpath to check for virtio to deal with poll() quirks */ @@ -567,31 +565,6 @@ static void dispatch_return_cb(QmpSession *session, QDict *rsp) } } -/* handle requests/control events coming in over the channel */ -static void process_event(void *opaque, QObject *obj, Error *err) -{ - GAState *s = opaque; - int ret; - - g_debug("process_event: called"); - assert(!obj != !err); - - if (err) { - QDict *rsp = qmp_error_response(err); - - ret = send_response(s, rsp); - if (ret < 0) { - g_warning("error sending error response: %s", strerror(-ret)); - } - qobject_unref(rsp); - } else { - g_debug("processing command"); - qmp_dispatch(&s->session, obj, false); - } - - qobject_unref(obj); -} - /* false return signals GAChannel to close the current client connection */ static gboolean channel_event_cb(GIOCondition condition, gpointer data) { @@ -607,7 +580,7 @@ static gboolean channel_event_cb(GIOCondition condition, gpointer data) case G_IO_STATUS_NORMAL: buf[count] = 0; g_debug("read data, count: %d, data: %s", (int)count, buf); - json_message_parser_feed(&s->parser, (char *)buf, (int)count); + qmp_session_feed(&s->session, (char *)buf, (int)count); break; case G_IO_STATUS_EOF: g_debug("received EOF"); @@ -1346,7 +1319,6 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation) s->command_state = ga_command_state_new(); ga_command_state_init(s, s->command_state); ga_command_state_init_all(s->command_state); - json_message_parser_init(&s->parser, process_event, s, NULL); qmp_session_init(&s->session, &ga_commands, dispatch_return_cb); #ifndef _WIN32 @@ -1382,7 +1354,6 @@ static void cleanup_agent(GAState *s) qmp_session_destroy(&s->session); ga_command_state_cleanup_all(s->command_state); ga_command_state_free(s->command_state); - json_message_parser_destroy(&s->parser); } g_free(s->pstate_filepath); g_free(s->state_filepath_isfrozen); From patchwork Fri Nov 8 15:01:04 2019 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: 11235063 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C4ABF13BD for ; Fri, 8 Nov 2019 15:05:15 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9B328215EA for ; Fri, 8 Nov 2019 15:05:15 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="W48h9ZUh" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9B328215EA Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:55878 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5p4-0005WW-9V for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:05:14 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:46194) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5mt-0003PX-Ul for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:03:01 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5ms-0003rS-Ap for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:02:59 -0500 Received: from us-smtp-delivery-1.mimecast.com ([207.211.31.120]:57130 helo=us-smtp-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5ms-0003rK-7F for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:02:58 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225377; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Q1Q4UMSoZSlz6+5iKyAOerNgelL9ZOigeHM/bJLClc4=; b=W48h9ZUh1RlALPZ1Ss8B8Xu0QKMuWL3zmhRJuwxTo22tUgxipMSXMF39wg700fOGvLUV9T g3QO8Acbq/qpPC+x5zMGdkmBl+jWozTwpb6rBfeDZ0HrarHCaqrE9kyrlZHXK9MHPlY/6L 4xV4q8hcHNtF356f72B/9FgbIvVTZTM= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-99-vJUwHQDvMV6MZxD6_cHMtw-1; Fri, 08 Nov 2019 10:02:56 -0500 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id C8138180496F for ; Fri, 8 Nov 2019 15:02:55 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8D0F05DA7F; Fri, 8 Nov 2019 15:02:48 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 06/25] monitor: use qmp session to parse json feed Date: Fri, 8 Nov 2019 19:01:04 +0400 Message-Id: <20191108150123.12213-7-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-MC-Unique: vJUwHQDvMV6MZxD6_cHMtw-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 207.211.31.120 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" Use the QmpSession json parser introduced in previous patch to generalize the handling in both qemu & qemu-ga. Unfortunately, since the introduction of OOB, it's not as common as it was before that. We may want to move some of OOB logic in common qmp-dispatch.c/QmpSession though. The QEMU monitor has peculiar handling of the stream of commands, for OOB command processing, which can be solved by overriding the json emit callback. Signed-off-by: Marc-André Lureau --- include/qapi/qmp/dispatch.h | 1 + include/qapi/qmp/json-parser.h | 7 ++++--- monitor/monitor-internal.h | 1 - monitor/qmp.c | 13 +++++-------- qapi/qmp-dispatch.c | 4 +++- qga/main.c | 2 +- qobject/json-streamer.c | 3 +-- tests/test-qmp-cmds.c | 11 ++++++----- 8 files changed, 21 insertions(+), 21 deletions(-) diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h index c84edff7d2..b3ca6c9ff2 100644 --- a/include/qapi/qmp/dispatch.h +++ b/include/qapi/qmp/dispatch.h @@ -53,6 +53,7 @@ const QmpCommand *qmp_find_command(const QmpCommandList *cmds, const char *name); void qmp_session_init(QmpSession *session, const QmpCommandList *cmds, + JSONMessageEmit *emit, QmpDispatchReturn *return_cb); static inline void qmp_session_feed(QmpSession *session, const char *buf, size_t count) diff --git a/include/qapi/qmp/json-parser.h b/include/qapi/qmp/json-parser.h index 7345a9bd5c..6f168e8007 100644 --- a/include/qapi/qmp/json-parser.h +++ b/include/qapi/qmp/json-parser.h @@ -14,6 +14,8 @@ #ifndef QAPI_QMP_JSON_PARSER_H #define QAPI_QMP_JSON_PARSER_H +typedef void (JSONMessageEmit)(void *opaque, QObject *json, Error *err); + typedef struct JSONLexer { int start_state, state; GString *token; @@ -21,7 +23,7 @@ typedef struct JSONLexer { } JSONLexer; typedef struct JSONMessageParser { - void (*emit)(void *opaque, QObject *json, Error *err); + JSONMessageEmit *emit; void *opaque; va_list *ap; JSONLexer lexer; @@ -32,8 +34,7 @@ typedef struct JSONMessageParser { } JSONMessageParser; void json_message_parser_init(JSONMessageParser *parser, - void (*emit)(void *opaque, QObject *json, - Error *err), + JSONMessageEmit *emit, void *opaque, va_list *ap); void json_message_parser_feed(JSONMessageParser *parser, diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h index b15266e77b..b8994f896a 100644 --- a/monitor/monitor-internal.h +++ b/monitor/monitor-internal.h @@ -124,7 +124,6 @@ struct MonitorHMP { typedef struct { Monitor common; - JSONMessageParser parser; bool pretty; /* * When a client connects, we're in capabilities negotiation mode. diff --git a/monitor/qmp.c b/monitor/qmp.c index b215cb70f3..cd29494e28 100644 --- a/monitor/qmp.c +++ b/monitor/qmp.c @@ -217,7 +217,7 @@ void monitor_qmp_bh_dispatcher(void *data) static void handle_qmp_command(void *opaque, QObject *req, Error *err) { - MonitorQMP *mon = opaque; + MonitorQMP *mon = container_of(opaque, MonitorQMP, session); QObject *id = NULL; QDict *qdict; QMPRequest *req_obj; @@ -279,7 +279,7 @@ static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size) { MonitorQMP *mon = opaque; - json_message_parser_feed(&mon->parser, (const char *) buf, size); + qmp_session_feed(&mon->session, (const char *) buf, size); } static QDict *qmp_greeting(MonitorQMP *mon) @@ -309,7 +309,9 @@ static void monitor_qmp_event(void *opaque, int event) switch (event) { case CHR_EVENT_OPENED: qmp_session_init(&mon->session, - &qmp_cap_negotiation_commands, dispatch_return_cb); + &qmp_cap_negotiation_commands, + handle_qmp_command, + dispatch_return_cb); monitor_qmp_caps_reset(mon); data = qmp_greeting(mon); qmp_send_response(mon, data); @@ -325,9 +327,6 @@ static void monitor_qmp_event(void *opaque, int event) */ monitor_qmp_cleanup_queues(mon); qmp_session_destroy(&mon->session); - json_message_parser_destroy(&mon->parser); - json_message_parser_init(&mon->parser, handle_qmp_command, - mon, NULL); mon_refcount--; monitor_fdsets_cleanup(); break; @@ -337,7 +336,6 @@ static void monitor_qmp_event(void *opaque, int event) void monitor_data_destroy_qmp(MonitorQMP *mon) { qmp_session_destroy(&mon->session); - json_message_parser_destroy(&mon->parser); qemu_mutex_destroy(&mon->qmp_queue_lock); monitor_qmp_cleanup_req_queue_locked(mon); g_queue_free(mon->qmp_requests); @@ -373,7 +371,6 @@ void monitor_init_qmp(Chardev *chr, bool pretty) qemu_chr_fe_init(&mon->common.chr, chr, &error_abort); qemu_chr_fe_set_echo(&mon->common.chr, true); - json_message_parser_init(&mon->parser, handle_qmp_command, mon, NULL); if (mon->common.use_io_thread) { /* * Make sure the old iowatch is gone. It's possible when diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index f8c491924d..b004d7506f 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -183,12 +183,14 @@ static void qmp_json_emit(void *opaque, QObject *obj, Error *err) void qmp_session_init(QmpSession *session, const QmpCommandList *cmds, + JSONMessageEmit *emit, QmpDispatchReturn *return_cb) { assert(return_cb); assert(!session->return_cb); - json_message_parser_init(&session->parser, qmp_json_emit, session, NULL); + json_message_parser_init(&session->parser, emit ?: qmp_json_emit, + session, NULL); session->cmds = cmds; session->return_cb = return_cb; } diff --git a/qga/main.c b/qga/main.c index 057368eb16..b005550c70 100644 --- a/qga/main.c +++ b/qga/main.c @@ -1319,7 +1319,7 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation) s->command_state = ga_command_state_new(); ga_command_state_init(s, s->command_state); ga_command_state_init_all(s->command_state); - qmp_session_init(&s->session, &ga_commands, dispatch_return_cb); + qmp_session_init(&s->session, &ga_commands, NULL, dispatch_return_cb); #ifndef _WIN32 if (!register_signal_handlers()) { diff --git a/qobject/json-streamer.c b/qobject/json-streamer.c index 47dd7ea576..2a440f2a9e 100644 --- a/qobject/json-streamer.c +++ b/qobject/json-streamer.c @@ -100,8 +100,7 @@ out_emit: } void json_message_parser_init(JSONMessageParser *parser, - void (*emit)(void *opaque, QObject *json, - Error *err), + JSONMessageEmit *emit, void *opaque, va_list *ap) { parser->emit = emit; diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c index cca15e79ba..d9623d10b6 100644 --- a/tests/test-qmp-cmds.c +++ b/tests/test-qmp-cmds.c @@ -155,7 +155,7 @@ static void test_dispatch_cmd(void) QmpSession session = { 0, }; QDict *req = qdict_new(); - qmp_session_init(&session, &qmp_commands, dispatch_cmd_return); + qmp_session_init(&session, &qmp_commands, NULL, dispatch_cmd_return); qdict_put_str(req, "execute", "user_def_cmd"); qmp_dispatch(&session, QOBJECT(req), false); @@ -169,7 +169,7 @@ static void test_dispatch_cmd_oob(void) QmpSession session = { 0, }; QDict *req = qdict_new(); - qmp_session_init(&session, &qmp_commands, dispatch_cmd_return); + qmp_session_init(&session, &qmp_commands, NULL, dispatch_cmd_return); qdict_put_str(req, "exec-oob", "test-flags-command"); qmp_dispatch(&session, QOBJECT(req), true); @@ -191,7 +191,8 @@ static void test_dispatch_cmd_failure(void) QDict *req = qdict_new(); QDict *args = qdict_new(); - qmp_session_init(&session, &qmp_commands, dispatch_cmd_failure_return); + qmp_session_init(&session, &qmp_commands, NULL, + dispatch_cmd_failure_return); qdict_put_str(req, "execute", "user_def_cmd2"); qmp_dispatch(&session, QOBJECT(req), false); @@ -217,7 +218,7 @@ static void test_dispatch_cmd_success_response(void) QmpSession session = { 0, }; QDict *req = qdict_new(); - qmp_session_init(&session, &qmp_commands, (QmpDispatchReturn *)abort); + qmp_session_init(&session, &qmp_commands, NULL, (QmpDispatchReturn *)abort); qdict_put_str(req, "execute", "cmd-success-response"); qmp_dispatch(&session, QOBJECT(req), false); @@ -238,7 +239,7 @@ static QObject *test_qmp_dispatch(QDict *req) QmpSession session = { 0, }; QObject *ret; - qmp_session_init(&session, &qmp_commands, dispatch_return); + qmp_session_init(&session, &qmp_commands, NULL, dispatch_return); qmp_dispatch(&session, QOBJECT(req), false); ret = dispatch_ret; dispatch_ret = NULL; From patchwork Fri Nov 8 15:01:05 2019 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: 11235083 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 14E0D1390 for ; Fri, 8 Nov 2019 15:13:01 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id E1030215EA for ; Fri, 8 Nov 2019 15:13:00 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="CI5XVGQ5" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E1030215EA Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:55980 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5wZ-0007Ra-Hq for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:12:59 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:46242) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5nD-0003mf-N3 for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:03:24 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5nA-00044J-Qp for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:03:19 -0500 Received: from us-smtp-2.mimecast.com ([205.139.110.61]:26661 helo=us-smtp-delivery-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5nA-00042v-Ke for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:03:16 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225396; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Nunur+v8C6yUd2Ig0aPCWyll3+RfwG+OyCvKxZXgQ6w=; b=CI5XVGQ5/QqN/gx2RlfVvJGQpuzq5ynAs6lBnE3SxGd55rG6pycSRxSIrhH6RR/uWB7qJ/ fPV9erCwM/jzYEzVBI0Kzzcv3VdwnmsflxNiqpdQpOyDBOXWU7E/F8FCBK40mRPaHi4UP6 k6l01PcjdZA3lXCitT7QdRgA6uM3b6o= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-114-FaHNDH-QMOS0q3r8iX7A9g-1; Fri, 08 Nov 2019 10:03:14 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 648D2180496F for ; Fri, 8 Nov 2019 15:03:13 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 6EC505C1BB; Fri, 8 Nov 2019 15:03:00 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 07/25] qga: simplify dispatch_return_cb Date: Fri, 8 Nov 2019 19:01:05 +0400 Message-Id: <20191108150123.12213-8-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-MC-Unique: FaHNDH-QMOS0q3r8iX7A9g-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 205.139.110.61 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" Fold send_response(). qobject_to_json() can't return NULL (it will crash if allocation failed, either in memcpy() or abort from g_realloc()). Signed-off-by: Marc-André Lureau --- qga/main.c | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/qga/main.c b/qga/main.c index b005550c70..66fe7ac3de 100644 --- a/qga/main.c +++ b/qga/main.c @@ -522,8 +522,9 @@ fail: #endif } -static int send_response(GAState *s, const QDict *rsp) +static void dispatch_return_cb(QmpSession *session, QDict *rsp) { + GAState *s = container_of(session, GAState, session); const char *buf; QString *payload_qstr, *response_qstr; GIOStatus status; @@ -531,9 +532,6 @@ static int send_response(GAState *s, const QDict *rsp) g_assert(rsp && s->channel); payload_qstr = qobject_to_json(QOBJECT(rsp)); - if (!payload_qstr) { - return -EINVAL; - } if (s->delimit_response) { s->delimit_response = false; @@ -550,18 +548,7 @@ static int send_response(GAState *s, const QDict *rsp) status = ga_channel_write_all(s->channel, buf, strlen(buf)); qobject_unref(response_qstr); if (status != G_IO_STATUS_NORMAL) { - return -EIO; - } - - return 0; -} - -static void dispatch_return_cb(QmpSession *session, QDict *rsp) -{ - GAState *s = container_of(session, GAState, session); - int ret = send_response(s, rsp); - if (ret < 0) { - g_warning("error sending response: %s", strerror(-ret)); + g_warning("Failed sending response"); } } From patchwork Fri Nov 8 15:01:06 2019 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: 11235071 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id ABDCE1390 for ; Fri, 8 Nov 2019 15:07:58 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 83203215EA for ; Fri, 8 Nov 2019 15:07:58 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="IWas4kgF" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 83203215EA Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:55926 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5rh-0000tw-64 for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:07:57 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:46337) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5nO-0003wv-Mo for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:03:32 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5nN-0004JT-1S for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:03:30 -0500 Received: from us-smtp-delivery-1.mimecast.com ([207.211.31.120]:36158 helo=us-smtp-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5nM-0004J7-Tk for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:03:28 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225408; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=g22iItwlMApoL+VpbZVGZPNFEpy+0XtGmVHDjP7V2QM=; b=IWas4kgFCgxnqP6uAZ53dNwPFxdCEzA96/oML/hHei313ZRXNCsj/4mVhNCw+xxET1vzSO JfeGmnCOA7ej4rxBp7B+evkvSSuBOVK5nnB5VFzQMJZvGeTsRnzVrL6k3WUUx9Qiiew/0x zEld6R2Hlcpqp5Eb3kAgwbKI8lRZwbw= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-159-YEJcvzrhO9WSj3E5UJYoJQ-1; Fri, 08 Nov 2019 10:03:27 -0500 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 7105E1804971 for ; Fri, 8 Nov 2019 15:03:26 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id BC86F600C9; Fri, 8 Nov 2019 15:03:19 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 08/25] QmpSession: introduce QmpReturn Date: Fri, 8 Nov 2019 19:01:06 +0400 Message-Id: <20191108150123.12213-9-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-MC-Unique: YEJcvzrhO9WSj3E5UJYoJQ-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 207.211.31.120 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" QmpReturn (and associated functions) is used during synchronous dispatch return for now. It helps to factor out some code for handling a reply context. In the following patches, the QmpReturn will be the basis upon which asynchronous reply will be handled: it will hold the context for a QMP command reply. Signed-off-by: Marc-André Lureau --- include/qapi/qmp/dispatch.h | 34 ++++++++++++++++- monitor/qmp.c | 6 +-- qapi/qmp-dispatch.c | 74 ++++++++++++++++++++++--------------- 3 files changed, 79 insertions(+), 35 deletions(-) diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h index b3ca6c9ff2..6c0d21968e 100644 --- a/include/qapi/qmp/dispatch.h +++ b/include/qapi/qmp/dispatch.h @@ -17,6 +17,8 @@ #include "qemu/queue.h" #include "qapi/qmp/json-parser.h" +typedef struct QmpReturn QmpReturn; + typedef void (QmpCommandFunc)(QDict *, QObject **, Error **); typedef enum QmpCommandOptions @@ -47,6 +49,37 @@ struct QmpSession { QmpDispatchReturn *return_cb; }; +struct QmpReturn { + QmpSession *session; + QDict *rsp; +}; + +/** + * qmp_return_new: + * + * Allocates and initializes a QmpReturn. + */ +QmpReturn *qmp_return_new(QmpSession *session, const QObject *req); + +/** + * qmp_return_free: + * + * Free a QmpReturn. This shouldn't be needed if you actually return + * with qmp_return{_error}. + */ +void qmp_return_free(QmpReturn *qret); + +/** + * qmp_return{_error}: + * + * Construct the command reply, and call the + * return_cb() associated with the session. + * + * Finally, free the QmpReturn. + */ +void qmp_return(QmpReturn *qret, QObject *rsp); +void qmp_return_error(QmpReturn *qret, Error *err); + void qmp_register_command(QmpCommandList *cmds, const char *name, QmpCommandFunc *fn, QmpCommandOptions options); const QmpCommand *qmp_find_command(const QmpCommandList *cmds, @@ -67,7 +100,6 @@ void qmp_enable_command(QmpCommandList *cmds, const char *name); bool qmp_command_is_enabled(const QmpCommand *cmd); const char *qmp_command_name(const QmpCommand *cmd); bool qmp_has_success_response(const QmpCommand *cmd); -QDict *qmp_error_response(Error *err); void qmp_dispatch(QmpSession *session, QObject *request, bool allow_oob); bool qmp_is_oob(const QDict *dict); diff --git a/monitor/qmp.c b/monitor/qmp.c index cd29494e28..056ad7b68b 100644 --- a/monitor/qmp.c +++ b/monitor/qmp.c @@ -179,7 +179,6 @@ static QMPRequest *monitor_qmp_requests_pop_any_with_lock(void) void monitor_qmp_bh_dispatcher(void *data) { QMPRequest *req_obj = monitor_qmp_requests_pop_any_with_lock(); - QDict *rsp; bool need_resume; MonitorQMP *mon; @@ -198,11 +197,10 @@ void monitor_qmp_bh_dispatcher(void *data) trace_monitor_qmp_cmd_in_band(qobject_get_try_str(id) ?: ""); monitor_qmp_dispatch(mon, req_obj->req); } else { + QmpSession *session = &req_obj->mon->session; assert(req_obj->err); - rsp = qmp_error_response(req_obj->err); + qmp_return_error(qmp_return_new(session, req_obj->req), req_obj->err); req_obj->err = NULL; - qmp_send_response(req_obj->mon, rsp); - qobject_unref(rsp); } if (need_resume) { diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index b004d7506f..188b5680b6 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -19,6 +19,46 @@ #include "sysemu/runstate.h" #include "qapi/qmp/qbool.h" +QmpReturn *qmp_return_new(QmpSession *session, const QObject *request) +{ + QmpReturn *qret = g_new0(QmpReturn, 1); + const QDict *req = qobject_to(QDict, request); + QObject *id = req ? qdict_get(req, "id") : NULL; + + qret->session = session; + qret->rsp = qdict_new(); + if (id) { + qobject_ref(id); + qdict_put_obj(qret->rsp, "id", id); + } + + return qret; +} + +void qmp_return_free(QmpReturn *qret) +{ + qobject_unref(qret->rsp); + g_free(qret); +} + +void qmp_return(QmpReturn *qret, QObject *rsp) +{ + qdict_put_obj(qret->rsp, "return", rsp ?: QOBJECT(qdict_new())); + qret->session->return_cb(qret->session, qret->rsp); + qmp_return_free(qret); +} + +void qmp_return_error(QmpReturn *qret, Error *err) +{ + qdict_put_obj(qret->rsp, "error", + qobject_from_jsonf_nofail("{ 'class': %s, 'desc': %s }", + QapiErrorClass_str(error_get_class(err)), + error_get_pretty(err))); + error_free(err); + qret->session->return_cb(qret->session, qret->rsp); + qmp_return_free(qret); +} + static QDict *qmp_dispatch_check_obj(const QObject *request, bool allow_oob, Error **errp) { @@ -144,17 +184,6 @@ static QObject *do_qmp_dispatch(const QmpCommandList *cmds, QObject *request, return ret; } -QDict *qmp_error_response(Error *err) -{ - QDict *rsp; - - rsp = qdict_from_jsonf_nofail("{ 'error': { 'class': %s, 'desc': %s } }", - QapiErrorClass_str(error_get_class(err)), - error_get_pretty(err)); - error_free(err); - return rsp; -} - /* * Does @qdict look like a command to be run out-of-band? */ @@ -171,9 +200,7 @@ static void qmp_json_emit(void *opaque, QObject *obj, Error *err) assert(!obj != !err); if (err) { - QDict *rsp = qmp_error_response(err); - session->return_cb(session, rsp); - qobject_unref(rsp); + qmp_return_error(qmp_return_new(session, obj), err); } else { qmp_dispatch(session, obj, false); } @@ -209,25 +236,12 @@ void qmp_session_destroy(QmpSession *session) void qmp_dispatch(QmpSession *session, QObject *request, bool allow_oob) { Error *err = NULL; - QDict *dict = qobject_to(QDict, request); - QObject *ret, *id = dict ? qdict_get(dict, "id") : NULL; - QDict *rsp; + QObject *ret; ret = do_qmp_dispatch(session->cmds, request, allow_oob, &err); if (err) { - rsp = qmp_error_response(err); + qmp_return_error(qmp_return_new(session, request), err); } else if (ret) { - rsp = qdict_new(); - qdict_put_obj(rsp, "return", ret); - } else { - /* Can only happen for commands with QCO_NO_SUCCESS_RESP */ - return; + qmp_return(qmp_return_new(session, request), ret); } - - if (id) { - qdict_put_obj(rsp, "id", qobject_ref(id)); - } - - session->return_cb(session, rsp); - qobject_unref(rsp); } From patchwork Fri Nov 8 15:01:07 2019 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: 11235091 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CD50E1709 for ; Fri, 8 Nov 2019 15:16:35 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id A051D214DB for ; Fri, 8 Nov 2019 15:16:35 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="a0nGYUQl" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org A051D214DB Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:56026 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT602-0002so-Bc for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:16:34 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:46414) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5nd-0004Jz-Dp for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:03:46 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5nc-0004RF-Be for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:03:45 -0500 Received: from us-smtp-delivery-1.mimecast.com ([207.211.31.120]:38876 helo=us-smtp-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5nc-0004R5-6Y for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:03:44 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225423; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=zvIOX9sTV8g3eSq1Z5naFU5517bwNh6zcozKMv6s9c0=; b=a0nGYUQl/zB3T6c4yTEIElVem2V3naygq2au+bPI1OjK0Hq2uqmvykTa5uBu6BmgI20O6D hMj8rJmmTboVB8IWCPDXwY3MbUym64+AF6G0QBAwzQV9tSfo7ctXe2a7dZLrDinkpfRVik NW049wsIohH1wB1KlQFMDyvZmUX2xrY= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-387-nJi0IT7iMj-CQRu7_tJwsQ-1; Fri, 08 Nov 2019 10:03:42 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 93E32477 for ; Fri, 8 Nov 2019 15:03:41 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9F2DD5C1BB; Fri, 8 Nov 2019 15:03:31 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 09/25] qmp: simplify qmp_return_error() Date: Fri, 8 Nov 2019 19:01:07 +0400 Message-Id: <20191108150123.12213-10-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-MC-Unique: nJi0IT7iMj-CQRu7_tJwsQ-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 207.211.31.120 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" It's simple, probably more efficient, to hand-craft the dict. Signed-off-by: Marc-André Lureau --- qapi/qmp-dispatch.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index 188b5680b6..fcf6cb0bf8 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -50,10 +50,10 @@ void qmp_return(QmpReturn *qret, QObject *rsp) void qmp_return_error(QmpReturn *qret, Error *err) { - qdict_put_obj(qret->rsp, "error", - qobject_from_jsonf_nofail("{ 'class': %s, 'desc': %s }", - QapiErrorClass_str(error_get_class(err)), - error_get_pretty(err))); + QDict *qdict = qdict_new(); + qdict_put_str(qdict, "class", QapiErrorClass_str(error_get_class(err))); + qdict_put_str(qdict, "desc", error_get_pretty(err)); + qdict_put_obj(qret->rsp, "error", QOBJECT(qdict)); error_free(err); qret->session->return_cb(qret->session, qret->rsp); qmp_return_free(qret); From patchwork Fri Nov 8 15:01:08 2019 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: 11235077 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6A22F13BD for ; Fri, 8 Nov 2019 15:10:24 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 4169A215EA for ; Fri, 8 Nov 2019 15:10:24 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="RwDVLt9d" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4169A215EA Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:55950 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5u2-0004Ir-Uv for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:10:23 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:46441) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5nq-0004Rl-H3 for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:03:59 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5no-0004ZT-LZ for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:03:58 -0500 Received: from us-smtp-delivery-1.mimecast.com ([207.211.31.120]:45748 helo=us-smtp-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5no-0004ZL-Hs for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:03:56 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225436; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=tokP4vjSso+mNJQryUKg0EPaJ0vjrJNzrRiRGvfAkFI=; b=RwDVLt9dHEDvbUQKDDRXvEEAhX2g0rsUSxv9FDIvt9QAoavnegr3LgEykWpoNhzn6zp2S0 wOqnXrsWlxDzGAUt47BUpuSK7kXlQf1KI3lO0VHeEoBaVSZ28JbWVZaqG9qstIcNOX0DLD 2d3EjTmszHUF1mRu8H9ZUScqLzXHP1I= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-215-qe37uHoCO7yql5MqneRGJg-1; Fri, 08 Nov 2019 10:03:54 -0500 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id C71E7180496F for ; Fri, 8 Nov 2019 15:03:53 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id E519060BE2; Fri, 8 Nov 2019 15:03:46 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 10/25] QmpSession: keep a queue of pending commands Date: Fri, 8 Nov 2019 19:01:08 +0400 Message-Id: <20191108150123.12213-11-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-MC-Unique: qe37uHoCO7yql5MqneRGJg-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 207.211.31.120 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" The following commit will introduce asynchronous commands. Let's keep the session aware of the pending commands, so we can do interesting things like order the replies, or cancel pending operations when the client is gone. The queue needs a lock, since QmpReturn may be called from any thread. Signed-off-by: Marc-André Lureau --- include/qapi/qmp/dispatch.h | 4 ++++ qapi/qmp-dispatch.c | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h index 6c0d21968e..7c9de9780d 100644 --- a/include/qapi/qmp/dispatch.h +++ b/include/qapi/qmp/dispatch.h @@ -16,6 +16,7 @@ #include "qemu/queue.h" #include "qapi/qmp/json-parser.h" +#include "qemu/thread.h" typedef struct QmpReturn QmpReturn; @@ -47,11 +48,14 @@ struct QmpSession { const QmpCommandList *cmds; JSONMessageParser parser; QmpDispatchReturn *return_cb; + QemuMutex pending_lock; + QTAILQ_HEAD(, QmpReturn) pending; }; struct QmpReturn { QmpSession *session; QDict *rsp; + QTAILQ_ENTRY(QmpReturn) entry; }; /** diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index fcf6cb0bf8..aed5c91057 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -32,11 +32,24 @@ QmpReturn *qmp_return_new(QmpSession *session, const QObject *request) qdict_put_obj(qret->rsp, "id", id); } + qemu_mutex_lock(&session->pending_lock); + QTAILQ_INSERT_TAIL(&session->pending, qret, entry); + qemu_mutex_unlock(&session->pending_lock); + return qret; } void qmp_return_free(QmpReturn *qret) { + QmpSession *session = qret->session; + + if (session) { + qemu_mutex_lock(&session->pending_lock); + } + QTAILQ_REMOVE(&session->pending, qret, entry); + if (session) { + qemu_mutex_unlock(&session->pending_lock); + } qobject_unref(qret->rsp); g_free(qret); } @@ -44,7 +57,9 @@ void qmp_return_free(QmpReturn *qret) void qmp_return(QmpReturn *qret, QObject *rsp) { qdict_put_obj(qret->rsp, "return", rsp ?: QOBJECT(qdict_new())); - qret->session->return_cb(qret->session, qret->rsp); + if (qret->session) { + qret->session->return_cb(qret->session, qret->rsp); + } qmp_return_free(qret); } @@ -55,7 +70,9 @@ void qmp_return_error(QmpReturn *qret, Error *err) qdict_put_str(qdict, "desc", error_get_pretty(err)); qdict_put_obj(qret->rsp, "error", QOBJECT(qdict)); error_free(err); - qret->session->return_cb(qret->session, qret->rsp); + if (qret->session) { + qret->session->return_cb(qret->session, qret->rsp); + } qmp_return_free(qret); } @@ -220,17 +237,28 @@ void qmp_session_init(QmpSession *session, session, NULL); session->cmds = cmds; session->return_cb = return_cb; + qemu_mutex_init(&session->pending_lock); + QTAILQ_INIT(&session->pending); } void qmp_session_destroy(QmpSession *session) { + QmpReturn *ret, *next; + if (!session->return_cb) { return; } + qemu_mutex_lock(&session->pending_lock); + QTAILQ_FOREACH_SAFE(ret, &session->pending, entry, next) { + ret->session = NULL; + QTAILQ_REMOVE(&session->pending, ret, entry); + } + qemu_mutex_unlock(&session->pending_lock); session->cmds = NULL; session->return_cb = NULL; json_message_parser_destroy(&session->parser); + qemu_mutex_destroy(&session->pending_lock); } void qmp_dispatch(QmpSession *session, QObject *request, bool allow_oob) From patchwork Fri Nov 8 15:01:09 2019 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: 11235097 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 517D21709 for ; Fri, 8 Nov 2019 15:20:41 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 287192178F for ; Fri, 8 Nov 2019 15:20:41 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Pn/HBfOx" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 287192178F Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:56080 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT63z-0006eb-Md for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:20:39 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:46462) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5o1-0004ht-0i for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:04:10 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5nz-0004mk-HR for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:04:08 -0500 Received: from us-smtp-delivery-1.mimecast.com ([205.139.110.120]:53306 helo=us-smtp-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5nz-0004mX-0i for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:04:07 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225446; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=zikJ2amcMtcp+zTObXzjfOccch34WImCsoPOE/0vrII=; b=Pn/HBfOxpkDJN5nnjiB3V76OvknkMGuG8QZ7T5dNptHebRKHJ3jWaSYipGWKmOx+c+xRAK ihowhEGxegSxZkQdd0UJh0GyfZ3G1eA3zgyQnggbO1zbQxcEh1kRPA4Rf9JwpX5j4boUnq TX3xAe/N1RN1/Qx0+htVWEWWhsODiOA= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-20-xP5bygtFOMqhbk1Pe0FfNA-1; Fri, 08 Nov 2019 10:04:04 -0500 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 186ED8017DD for ; Fri, 8 Nov 2019 15:04:04 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 95BF85D6B7; Fri, 8 Nov 2019 15:03:59 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 11/25] QmpSession: return orderly Date: Fri, 8 Nov 2019 19:01:09 +0400 Message-Id: <20191108150123.12213-12-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-MC-Unique: xP5bygtFOMqhbk1Pe0FfNA-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 205.139.110.120 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" QEMU will gain support for asynchronous commands, and may thus finish commands in various order. However, the clients expect replies in order. Let's enforce ordering of replies in QmpReturn: starting from the older command, process each pending QmpReturn, and return until reaching one that is unfinished. Or if the command is OOB, it should return immediately. Signed-off-by: Marc-André Lureau --- include/qapi/qmp/dispatch.h | 2 ++ qapi/qmp-dispatch.c | 61 ++++++++++++++++++++++++++++++------- tests/test-qmp-cmds.c | 33 ++++++++++++++++++++ 3 files changed, 85 insertions(+), 11 deletions(-) diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h index 7c9de9780d..92d6fd1afb 100644 --- a/include/qapi/qmp/dispatch.h +++ b/include/qapi/qmp/dispatch.h @@ -55,6 +55,8 @@ struct QmpSession { struct QmpReturn { QmpSession *session; QDict *rsp; + bool oob; + bool finished; QTAILQ_ENTRY(QmpReturn) entry; }; diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index aed5c91057..3eb7e4b610 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -25,6 +25,7 @@ QmpReturn *qmp_return_new(QmpSession *session, const QObject *request) const QDict *req = qobject_to(QDict, request); QObject *id = req ? qdict_get(req, "id") : NULL; + qret->oob = req ? qmp_is_oob(req) : false; qret->session = session; qret->rsp = qdict_new(); if (id) { @@ -39,6 +40,15 @@ QmpReturn *qmp_return_new(QmpSession *session, const QObject *request) return qret; } +static void qmp_return_free_with_lock(QmpReturn *qret) +{ + if (qret->session) { + QTAILQ_REMOVE(&qret->session->pending, qret, entry); + } + qobject_unref(qret->rsp); + g_free(qret); +} + void qmp_return_free(QmpReturn *qret) { QmpSession *session = qret->session; @@ -46,21 +56,53 @@ void qmp_return_free(QmpReturn *qret) if (session) { qemu_mutex_lock(&session->pending_lock); } - QTAILQ_REMOVE(&session->pending, qret, entry); + + qmp_return_free_with_lock(qret); + if (session) { qemu_mutex_unlock(&session->pending_lock); } - qobject_unref(qret->rsp); - g_free(qret); +} + +static void qmp_return_orderly(QmpReturn *qret) +{ + QmpSession *session = qret->session; + QmpReturn *ret, *next; + + if (!session) { + /* the session was destroyed before return, discard */ + qmp_return_free(qret); + return; + } + if (qret->oob) { + session->return_cb(session, qret->rsp); + qmp_return_free(qret); + return; + } + + qret->finished = true; + + qemu_mutex_lock(&session->pending_lock); + /* + * Process the list of pending and call return_cb until reaching + * an unfinished. + */ + QTAILQ_FOREACH_SAFE(ret, &session->pending, entry, next) { + if (!ret->finished) { + break; + } + session->return_cb(session, ret->rsp); + ret->session = session; + qmp_return_free_with_lock(ret); + } + + qemu_mutex_unlock(&session->pending_lock); } void qmp_return(QmpReturn *qret, QObject *rsp) { qdict_put_obj(qret->rsp, "return", rsp ?: QOBJECT(qdict_new())); - if (qret->session) { - qret->session->return_cb(qret->session, qret->rsp); - } - qmp_return_free(qret); + qmp_return_orderly(qret); } void qmp_return_error(QmpReturn *qret, Error *err) @@ -70,10 +112,7 @@ void qmp_return_error(QmpReturn *qret, Error *err) qdict_put_str(qdict, "desc", error_get_pretty(err)); qdict_put_obj(qret->rsp, "error", QOBJECT(qdict)); error_free(err); - if (qret->session) { - qret->session->return_cb(qret->session, qret->rsp); - } - qmp_return_free(qret); + qmp_return_orderly(qret); } static QDict *qmp_dispatch_check_obj(const QObject *request, bool allow_oob, diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c index d9623d10b6..213df7e53a 100644 --- a/tests/test-qmp-cmds.c +++ b/tests/test-qmp-cmds.c @@ -361,6 +361,38 @@ static void test_dealloc_partial(void) qapi_free_UserDefTwo(ud2); } +typedef struct QmpReturnOrderly { + QmpSession session; + int returns; +} QmpReturnOrderly; + +static void dispatch_return_orderly(QmpSession *session, QDict *resp) +{ + QmpReturnOrderly *o = container_of(session, QmpReturnOrderly, session); + + o->returns++; +} + +static void test_qmp_return_orderly(void) +{ + QDict *dict = qdict_new(); + QmpReturnOrderly o = { { 0 }, }; + QmpReturn *r1, *r2, *r3; + + qmp_session_init(&o.session, &qmp_commands, NULL, dispatch_return_orderly); + r1 = qmp_return_new(&o.session, NULL); + qdict_put_str(dict, "exec-oob", "test"); + r2 = qmp_return_new(&o.session, QOBJECT(dict)); + r3 = qmp_return_new(&o.session, NULL); + qmp_return(r3, NULL); + g_assert_cmpint(o.returns, ==, 0); + qmp_return(r2, NULL); + g_assert_cmpint(o.returns, ==, 1); + qmp_return(r1, NULL); + g_assert_cmpint(o.returns, ==, 3); + qmp_session_destroy(&o.session); + qobject_unref(dict); +} int main(int argc, char **argv) { @@ -374,6 +406,7 @@ int main(int argc, char **argv) test_dispatch_cmd_success_response); g_test_add_func("/qmp/dealloc_types", test_dealloc_types); g_test_add_func("/qmp/dealloc_partial", test_dealloc_partial); + g_test_add_func("/qmp/return_orderly", test_qmp_return_orderly); test_qmp_init_marshal(&qmp_commands); g_test_run(); From patchwork Fri Nov 8 15:01:10 2019 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: 11235075 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4D6FA13BD for ; Fri, 8 Nov 2019 15:09:29 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 24F3E215EA for ; Fri, 8 Nov 2019 15:09:29 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="PRbYFbMH" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 24F3E215EA Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:55946 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5t8-00036a-S3 for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:09:26 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:46493) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5oH-0004th-3a for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:04:27 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5oF-0004u4-BM for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:04:24 -0500 Received: from us-smtp-2.mimecast.com ([205.139.110.61]:37175 helo=us-smtp-delivery-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5oE-0004tF-1u for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:04:22 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225461; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=qchnptFi058dP+AH94G/eZXd37hN440uraGqVjM2KYE=; b=PRbYFbMHAtVJyMQ0YpVOFq2H7oDjaESiaOex8SErkFVVIuP+zGSKVX8Y4P64X/UzEgAlVg U3BEvDWkLxmQnqUVzHQ6FbSivLQKcs/MGNww85YZaTPSRBQq2xyBDprTh4cQHR38IPeL/F 8P9p47uLisYD2Xed0VxL910xaAH9ch8= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-324-depKDAkFO_CFx_4sucFtuw-1; Fri, 08 Nov 2019 10:04:20 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 14252107ACC4 for ; Fri, 8 Nov 2019 15:04:19 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 388795C1BB; Fri, 8 Nov 2019 15:04:08 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 12/25] qmp: introduce asynchronous command type Date: Fri, 8 Nov 2019 19:01:10 +0400 Message-Id: <20191108150123.12213-13-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-MC-Unique: depKDAkFO_CFx_4sucFtuw-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 205.139.110.61 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" Add a new type of command, QmpCommandFuncAsync: those commands can return later thanks to QmpReturn. This commit introduces the new type and register function and teach qmp_dipatch() to call it without qmp_return(). The async_fn callback will be responsible for calling qmp_return(), either synchronously or asynchronously. Signed-off-by: Marc-André Lureau --- include/qapi/qmp/dispatch.h | 10 +++++++++- qapi/qmp-dispatch.c | 27 ++++++++++++++++----------- qapi/qmp-registry.c | 27 ++++++++++++++++++++++++--- 3 files changed, 49 insertions(+), 15 deletions(-) diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h index 92d6fd1afb..6aef0abc70 100644 --- a/include/qapi/qmp/dispatch.h +++ b/include/qapi/qmp/dispatch.h @@ -21,6 +21,7 @@ typedef struct QmpReturn QmpReturn; typedef void (QmpCommandFunc)(QDict *, QObject **, Error **); +typedef void (QmpCommandAsyncFunc)(QDict *, QmpReturn *); typedef enum QmpCommandOptions { @@ -28,12 +29,16 @@ typedef enum QmpCommandOptions QCO_NO_SUCCESS_RESP = (1U << 0), QCO_ALLOW_OOB = (1U << 1), QCO_ALLOW_PRECONFIG = (1U << 2), + QCO_ASYNC = (1U << 3), } QmpCommandOptions; typedef struct QmpCommand { const char *name; - QmpCommandFunc *fn; + union { + QmpCommandFunc *fn; + QmpCommandAsyncFunc *async_fn; + }; QmpCommandOptions options; QTAILQ_ENTRY(QmpCommand) node; bool enabled; @@ -88,6 +93,9 @@ void qmp_return_error(QmpReturn *qret, Error *err); void qmp_register_command(QmpCommandList *cmds, const char *name, QmpCommandFunc *fn, QmpCommandOptions options); +void qmp_register_async_command(QmpCommandList *cmds, const char *name, + QmpCommandAsyncFunc *fn, + QmpCommandOptions options); const QmpCommand *qmp_find_command(const QmpCommandList *cmds, const char *name); void qmp_session_init(QmpSession *session, diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index 3eb7e4b610..85e99671a9 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -171,7 +171,7 @@ static QDict *qmp_dispatch_check_obj(const QObject *request, bool allow_oob, return dict; } -static QObject *do_qmp_dispatch(const QmpCommandList *cmds, QObject *request, +static QObject *do_qmp_dispatch(QmpSession *session, QObject *request, bool allow_oob, Error **errp) { Error *local_err = NULL; @@ -193,7 +193,7 @@ static QObject *do_qmp_dispatch(const QmpCommandList *cmds, QObject *request, command = qdict_get_str(dict, "exec-oob"); oob = true; } - cmd = qmp_find_command(cmds, command); + cmd = qmp_find_command(session->cmds, command); if (cmd == NULL) { error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND, "The command %s has not been found", command); @@ -225,14 +225,19 @@ static QObject *do_qmp_dispatch(const QmpCommandList *cmds, QObject *request, qobject_ref(args); } - cmd->fn(args, &ret, &local_err); - if (local_err) { - error_propagate(errp, local_err); - } else if (cmd->options & QCO_NO_SUCCESS_RESP) { - g_assert(!ret); - } else if (!ret) { - /* TODO turn into assertion */ - ret = QOBJECT(qdict_new()); + + if (cmd->options & QCO_ASYNC) { + cmd->async_fn(args, qmp_return_new(session, request)); + } else { + cmd->fn(args, &ret, &local_err); + if (local_err) { + error_propagate(errp, local_err); + } else if (cmd->options & QCO_NO_SUCCESS_RESP) { + g_assert(!ret); + } else if (!ret) { + /* TODO turn into assertion */ + ret = QOBJECT(qdict_new()); + } } qobject_unref(args); @@ -305,7 +310,7 @@ void qmp_dispatch(QmpSession *session, QObject *request, bool allow_oob) Error *err = NULL; QObject *ret; - ret = do_qmp_dispatch(session->cmds, request, allow_oob, &err); + ret = do_qmp_dispatch(session, request, allow_oob, &err); if (err) { qmp_return_error(qmp_return_new(session, request), err); } else if (ret) { diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c index d0f9a1d3e3..0f3d521ce5 100644 --- a/qapi/qmp-registry.c +++ b/qapi/qmp-registry.c @@ -15,16 +15,37 @@ #include "qemu/osdep.h" #include "qapi/qmp/dispatch.h" -void qmp_register_command(QmpCommandList *cmds, const char *name, - QmpCommandFunc *fn, QmpCommandOptions options) + +static QmpCommand *qmp_command_new(QmpCommandList *cmds, const char *name, + QmpCommandOptions options) { QmpCommand *cmd = g_malloc0(sizeof(*cmd)); cmd->name = name; - cmd->fn = fn; cmd->enabled = true; cmd->options = options; QTAILQ_INSERT_TAIL(cmds, cmd, node); + + return cmd; +} + + +void qmp_register_command(QmpCommandList *cmds, const char *name, + QmpCommandFunc *fn, QmpCommandOptions options) +{ + QmpCommand *cmd = qmp_command_new(cmds, name, options); + + assert(!(options & QCO_ASYNC)); + cmd->fn = fn; +} + +void qmp_register_async_command(QmpCommandList *cmds, const char *name, + QmpCommandAsyncFunc *fn, QmpCommandOptions options) +{ + QmpCommand *cmd = qmp_command_new(cmds, name, options); + + assert(options & QCO_ASYNC); + cmd->async_fn = fn; } const QmpCommand *qmp_find_command(const QmpCommandList *cmds, const char *name) From patchwork Fri Nov 8 15:01:11 2019 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: 11235079 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E7E5D1390 for ; Fri, 8 Nov 2019 15:10:35 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id AD387215EA for ; Fri, 8 Nov 2019 15:10:35 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="RZSQKsJB" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org AD387215EA Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:55954 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5uE-0004cy-EY for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:10:34 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:46550) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5oY-00052s-7c for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:04:45 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5oU-00051n-0X for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:04:41 -0500 Received: from us-smtp-2.mimecast.com ([205.139.110.61]:50651 helo=us-smtp-delivery-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5oS-00050w-MU for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:04:37 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225476; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=MQo/RxsLCbRLIfn5dXPT7MLQoAPuvHzpSnZeI8LguL4=; b=RZSQKsJB3CivrQxO2pR3MLuf2X+FJlDoa15xazv4HQtpOwa5sIKYOjz+jH8UBRhHaWKUB4 ZJYLOMPF2FUxyZL2P/pZGPkTfDAVVOLas4idkaIcbbCoY2Fuj1vA816gPzLxUqvW4bbvCQ I+jnjerxCy9L+qdTYSYvMKAdRyQQtrY= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-296-rBaDBzpRMPS-4EJfV6kCIA-1; Fri, 08 Nov 2019 10:04:33 -0500 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 066A91005500 for ; Fri, 8 Nov 2019 15:04:33 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 6E58F60BE2; Fri, 8 Nov 2019 15:04:24 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 13/25] scripts: learn 'async' qapi commands Date: Fri, 8 Nov 2019 19:01:11 +0400 Message-Id: <20191108150123.12213-14-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-MC-Unique: rBaDBzpRMPS-4EJfV6kCIA-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 205.139.110.61 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" Commands with the 'async' key will be registered as async type (see related commit), and will allow a synchronous (in scope callback) or asynchronous return (out-of-scope when ready, in idle etc) by keeping the given QmpReturn and calling qmp_return function later. Ex: { 'command': 'foo-async, 'data': {'arg': 'str'}, 'returns': 'Foo', 'async': true } generates the following marshaller: void qmp_marshal_foo_async(QDict *args, QmpReturn *qret) { Error *err = NULL; Visitor *v; q_obj_foo_async_arg arg = {0}; v = qmp_input_visitor_new(QOBJECT(args), true); visit_start_struct(v, NULL, NULL, 0, &err); if (err) { goto out; } visit_type_q_obj_foo_async_arg_members(v, &arg, &err); if (!err) { visit_check_struct(v, &err); } visit_end_struct(v, NULL); if (err) { goto out; } qmp_foo_async(arg.arg, qret); out: if (err) { qmp_return_error(qret, err); } visit_free(v); v = qapi_dealloc_visitor_new(); visit_start_struct(v, NULL, NULL, 0, NULL); visit_type_q_obj_foo_async_arg_members(v, &arg, NULL); visit_end_struct(v, NULL); visit_free(v); } and a return helper: void qmp_foo_async_return(QmpReturn *qret, Foo *ret_in) { Error *err = NULL; QObject *ret_out = NULL; qmp_marshal_output_Foo(ret_in, &ret_out, &err); if (err) { qmp_return_error(qret, err); } else { qmp_return(qret, ret_out); } } The dispatched function may call the return helper within the calling scope or delay the return. To return an error, it can call qmp_return_error() directly instead. Signed-off-by: Marc-André Lureau --- scripts/qapi/commands.py | 149 ++++++++++++++++++++---- scripts/qapi/doc.py | 2 +- scripts/qapi/expr.py | 4 +- scripts/qapi/introspect.py | 2 +- scripts/qapi/schema.py | 11 +- tests/qapi-schema/qapi-schema-test.json | 5 + tests/qapi-schema/qapi-schema-test.out | 8 ++ tests/qapi-schema/test-qapi.py | 7 +- tests/test-qmp-cmds.c | 60 ++++++++++ 9 files changed, 212 insertions(+), 36 deletions(-) diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py index ab98e504f3..301b1a24d8 100644 --- a/scripts/qapi/commands.py +++ b/scripts/qapi/commands.py @@ -17,18 +17,35 @@ from qapi.common import * from qapi.gen import QAPIGenCCode, QAPISchemaModularCVisitor, ifcontext -def gen_command_decl(name, arg_type, boxed, ret_type): - return mcgen(''' +def gen_command_decl(name, arg_type, boxed, ret_type, success_response, asyn): + if asyn: + extra = "QmpReturn *qret" + else: + extra = 'Error **errp' + + if asyn: + ret = mcgen(''' +void qmp_%(name)s(%(params)s); + ''', + name=c_name(name), + params=build_params(arg_type, boxed, extra)) + if success_response: + ret += mcgen(''' +void qmp_%(name)s_return(QmpReturn *qret%(c_type)s); +''', + c_type=(", " + ret_type.c_type() if ret_type else ""), + name=c_name(name)) + return ret + else: + return mcgen(''' %(c_type)s qmp_%(c_name)s(%(params)s); ''', - c_type=(ret_type and ret_type.c_type()) or 'void', - c_name=c_name(name), - params=build_params(arg_type, boxed, 'Error **errp')) + c_type=(ret_type and ret_type.c_type()) or 'void', + c_name=c_name(name), + params=build_params(arg_type, boxed, extra)) -def gen_call(name, arg_type, boxed, ret_type): - ret = '' - +def gen_argstr(arg_type, boxed): argstr = '' if boxed: assert arg_type @@ -39,7 +56,13 @@ def gen_call(name, arg_type, boxed, ret_type): if memb.optional: argstr += 'arg.has_%s, ' % c_name(memb.name) argstr += 'arg.%s, ' % c_name(memb.name) + return argstr + +def gen_call(name, arg_type, boxed, ret_type): + ret = '' + + argstr = gen_argstr(arg_type, boxed) lhs = '' if ret_type: lhs = 'retval = ' @@ -61,6 +84,51 @@ def gen_call(name, arg_type, boxed, ret_type): return ret +def gen_async_call(name, arg_type, boxed): + argstr = gen_argstr(arg_type, boxed) + + push_indent() + ret = mcgen(''' + +qmp_%(c_name)s(%(args)sqret); +''', + c_name=c_name(name), args=argstr) + + pop_indent() + return ret + + +def gen_async_return(name, ret_type): + if ret_type: + return mcgen(''' + +void qmp_%(c_name)s_return(QmpReturn *qret, %(ret_type)s ret_in) +{ + Error *err = NULL; + QObject *ret_out = NULL; + + qmp_marshal_output_%(ret_c_name)s(ret_in, &ret_out, &err); + + if (err) { + qmp_return_error(qret, err); + } else { + qmp_return(qret, ret_out); + } +} +''', + c_name=c_name(name), + ret_type=ret_type.c_type(), ret_c_name=ret_type.c_name()) + else: + return mcgen(''' + +void qmp_%(c_name)s_return(QmpReturn *qret) +{ + qmp_return(qret, QOBJECT(qdict_new())); +} +''', + c_name=c_name(name)) + + def gen_marshal_output(ret_type): return mcgen(''' @@ -84,19 +152,22 @@ static void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in, QObject **ret_out, c_type=ret_type.c_type(), c_name=ret_type.c_name()) -def build_marshal_proto(name): - return ('void qmp_marshal_%s(QDict *args, QObject **ret, Error **errp)' - % c_name(name)) +def build_marshal_proto(name, asyn): + if asyn: + tmpl = 'void qmp_marshal_%s(QDict *args, QmpReturn *qret)' + else: + tmpl = 'void qmp_marshal_%s(QDict *args, QObject **ret, Error **errp)' + return tmpl % c_name(name) -def gen_marshal_decl(name): +def gen_marshal_decl(name, asyn): return mcgen(''' %(proto)s; ''', - proto=build_marshal_proto(name)) + proto=build_marshal_proto(name, asyn)) -def gen_marshal(name, arg_type, boxed, ret_type): +def gen_marshal(name, arg_type, boxed, ret_type, asyn): have_args = boxed or (arg_type and not arg_type.is_empty()) ret = mcgen(''' @@ -105,9 +176,9 @@ def gen_marshal(name, arg_type, boxed, ret_type): { Error *err = NULL; ''', - proto=build_marshal_proto(name)) + proto=build_marshal_proto(name, asyn)) - if ret_type: + if ret_type and not asyn: ret += mcgen(''' %(c_type)s retval; ''', @@ -154,12 +225,28 @@ def gen_marshal(name, arg_type, boxed, ret_type): } ''') - ret += gen_call(name, arg_type, boxed, ret_type) + if asyn: + ret += gen_async_call(name, arg_type, boxed) + else: + ret += gen_call(name, arg_type, boxed, ret_type) ret += mcgen(''' out: +''') + + if asyn: + ret += mcgen(''' + if (err) { + qmp_return_error(qret, err); + } +''') + else: + ret += mcgen(''' error_propagate(errp, err); +''') + + ret += mcgen(''' visit_free(v); ''') @@ -194,7 +281,8 @@ out: return ret -def gen_register_command(name, success_response, allow_oob, allow_preconfig): +def gen_register_command(name, success_response, allow_oob, allow_preconfig, + asyn): options = [] if not success_response: @@ -203,17 +291,24 @@ def gen_register_command(name, success_response, allow_oob, allow_preconfig): options += ['QCO_ALLOW_OOB'] if allow_preconfig: options += ['QCO_ALLOW_PRECONFIG'] + if asyn: + options += ['QCO_ASYNC'] if not options: options = ['QCO_NO_OPTIONS'] options = " | ".join(options) + if asyn: + regfn = 'qmp_register_async_command' + else: + regfn = 'qmp_register_command' + ret = mcgen(''' - qmp_register_command(cmds, "%(name)s", + %(regfn)s(cmds, "%(name)s", qmp_marshal_%(c_name)s, %(opts)s); ''', - name=name, c_name=c_name(name), + regfn=regfn, name=name, c_name=c_name(name), opts=options) return ret @@ -278,7 +373,7 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds); def visit_command(self, name, info, ifcond, arg_type, ret_type, gen, success_response, boxed, allow_oob, allow_preconfig, - features): + features, asyn): if not gen: return # FIXME: If T is a user-defined type, the user is responsible @@ -292,11 +387,15 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds); self._genh, self._genc, self._regy): self._genc.add(gen_marshal_output(ret_type)) with ifcontext(ifcond, self._genh, self._genc, self._regy): - self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type)) - self._genh.add(gen_marshal_decl(name)) - self._genc.add(gen_marshal(name, arg_type, boxed, ret_type)) + self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type, + success_response, asyn)) + self._genh.add(gen_marshal_decl(name, asyn)) + self._genc.add(gen_marshal(name, arg_type, boxed, ret_type, asyn)) + if asyn and success_response: + self._genc.add(gen_async_return(name, ret_type)) self._regy.add(gen_register_command(name, success_response, - allow_oob, allow_preconfig)) + allow_oob, allow_preconfig, + asyn)) def gen_commands(schema, output_dir, prefix): diff --git a/scripts/qapi/doc.py b/scripts/qapi/doc.py index 6f1c17f71f..375978f04f 100644 --- a/scripts/qapi/doc.py +++ b/scripts/qapi/doc.py @@ -265,7 +265,7 @@ class QAPISchemaGenDocVisitor(QAPISchemaVisitor): def visit_command(self, name, info, ifcond, arg_type, ret_type, gen, success_response, boxed, allow_oob, allow_preconfig, - features): + features, asyn): doc = self.cur_doc self._gen.add(texi_msg('Command', doc, ifcond, texi_arguments(doc, diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index d7a289eded..db4956133d 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -89,7 +89,7 @@ def check_flags(expr, info): if key in expr and expr[key] is not False: raise QAPISemError( info, "flag '%s' may only use false value" % key) - for key in ['boxed', 'allow-oob', 'allow-preconfig']: + for key in ['boxed', 'allow-oob', 'allow-preconfig', 'async']: if key in expr and expr[key] is not True: raise QAPISemError( info, "flag '%s' may only use true value" % key) @@ -344,7 +344,7 @@ def check_exprs(exprs): ['command'], ['data', 'returns', 'boxed', 'if', 'features', 'gen', 'success-response', 'allow-oob', - 'allow-preconfig']) + 'allow-preconfig', 'async']) normalize_members(expr.get('data')) check_command(expr, info) elif meta == 'event': diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py index b3a463dd8b..f28c96afa3 100644 --- a/scripts/qapi/introspect.py +++ b/scripts/qapi/introspect.py @@ -212,7 +212,7 @@ const QLitObject %(c_name)s = %(c_string)s; def visit_command(self, name, info, ifcond, arg_type, ret_type, gen, success_response, boxed, allow_oob, allow_preconfig, - features): + features, asyn): arg_type = arg_type or self._schema.the_empty_object_type ret_type = ret_type or self._schema.the_empty_object_type obj = {'arg-type': self._use_type(arg_type), diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py index cf0045f34e..2e1d5278bf 100644 --- a/scripts/qapi/schema.py +++ b/scripts/qapi/schema.py @@ -128,7 +128,7 @@ class QAPISchemaVisitor(object): def visit_command(self, name, info, ifcond, arg_type, ret_type, gen, success_response, boxed, allow_oob, allow_preconfig, - features): + features, asyn): pass def visit_event(self, name, info, ifcond, arg_type, boxed): @@ -678,7 +678,7 @@ class QAPISchemaCommand(QAPISchemaEntity): def __init__(self, name, info, doc, ifcond, arg_type, ret_type, gen, success_response, boxed, allow_oob, allow_preconfig, - features): + features, asyn): QAPISchemaEntity.__init__(self, name, info, doc, ifcond, features) assert not arg_type or isinstance(arg_type, str) assert not ret_type or isinstance(ret_type, str) @@ -691,6 +691,7 @@ class QAPISchemaCommand(QAPISchemaEntity): self.boxed = boxed self.allow_oob = allow_oob self.allow_preconfig = allow_preconfig + self.asyn = asyn def check(self, schema): QAPISchemaEntity.check(self, schema) @@ -733,7 +734,7 @@ class QAPISchemaCommand(QAPISchemaEntity): self.gen, self.success_response, self.boxed, self.allow_oob, self.allow_preconfig, - self.features) + self.features, self.asyn) class QAPISchemaEvent(QAPISchemaEntity): @@ -1016,6 +1017,7 @@ class QAPISchema(object): allow_preconfig = expr.get('allow-preconfig', False) ifcond = expr.get('if') features = expr.get('features', []) + asyn = expr.get('async', False) if isinstance(data, OrderedDict): data = self._make_implicit_object_type( name, info, ifcond, 'arg', self._make_members(data, info)) @@ -1025,7 +1027,8 @@ class QAPISchema(object): self._def_entity(QAPISchemaCommand(name, info, doc, ifcond, data, rets, gen, success_response, boxed, allow_oob, allow_preconfig, - self._make_features(features, info))) + self._make_features(features, info), + asyn)) def _def_event(self, expr, info, doc): name = expr['event'] diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index 9abf175fe0..58d2164c7e 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -148,6 +148,11 @@ { 'command': 'cmd-success-response', 'data': {}, 'success-response': false } +{ 'command': 'cmd-async', 'data': {'filename': 'str'}, + 'returns': 'Empty2', 'async': true } +{ 'command': 'cmd-success-response-async', 'data': {'filename': 'str'}, + 'async': true, 'success-response': false} + # Returning a non-dictionary requires a name from the whitelist { 'command': 'guest-get-time', 'data': {'a': 'int', '*b': 'int' }, 'returns': 'int' } diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index 3660e75a48..19d2d202b9 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -217,6 +217,14 @@ command user_def_cmd2 q_obj_user_def_cmd2-arg -> UserDefTwo gen=True success_response=True boxed=False oob=False preconfig=False command cmd-success-response None -> None gen=True success_response=False boxed=False oob=False preconfig=False +object q_obj_cmd-async-arg + member filename: str optional=False +command cmd-async q_obj_cmd-async-arg -> Empty2 + gen=True success_response=True boxed=False oob=False preconfig=False async=True +object q_obj_cmd-success-response-async-arg + member filename: str optional=False +command cmd-success-response-async q_obj_cmd-success-response-async-arg -> None + gen=True success_response=False boxed=False oob=False preconfig=False async=True object q_obj_guest-get-time-arg member a: int optional=False member b: int optional=True diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py index bad14edb47..1914b7d5ff 100755 --- a/tests/qapi-schema/test-qapi.py +++ b/tests/qapi-schema/test-qapi.py @@ -70,12 +70,13 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor): def visit_command(self, name, info, ifcond, arg_type, ret_type, gen, success_response, boxed, allow_oob, allow_preconfig, - features): + features, asyn): print('command %s %s -> %s' % (name, arg_type and arg_type.name, ret_type and ret_type.name)) - print(' gen=%s success_response=%s boxed=%s oob=%s preconfig=%s' - % (gen, success_response, boxed, allow_oob, allow_preconfig)) + print(' gen=%s success_response=%s boxed=%s oob=%s preconfig=%s%s' + % (gen, success_response, boxed, allow_oob, allow_preconfig, + ' async=True' if asyn else '')) self._print_if(ifcond) self._print_features(features) diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c index 213df7e53a..75ef30f6ea 100644 --- a/tests/test-qmp-cmds.c +++ b/tests/test-qmp-cmds.c @@ -34,6 +34,28 @@ void qmp_cmd_success_response(Error **errp) { } +static gboolean cmd_async_idle(gpointer user_data) +{ + QmpReturn *qret = user_data; + + qmp_cmd_async_return(qret, g_new0(Empty2, 1)); + + return G_SOURCE_REMOVE; +} + +void qmp_cmd_async(const char *filename, QmpReturn *qret) +{ + g_idle_add(cmd_async_idle, qret); +} + +void qmp_cmd_success_response_async(const char *filename, QmpReturn *qret) +{ + Error *err = NULL; + + error_setg(&err, "no response, but error ok"); + qmp_return_error(qret, err); +} + Empty2 *qmp_user_def_cmd0(Error **errp) { return g_new0(Empty2, 1); @@ -394,6 +416,43 @@ static void test_qmp_return_orderly(void) qobject_unref(dict); } +typedef struct QmpReturnAsync { + QmpSession session; + GMainLoop *loop; +} QmpReturnAsync; + +static void dispatch_return_async(QmpSession *session, QDict *resp) +{ + QmpReturnAsync *a = container_of(session, QmpReturnAsync, session); + + g_main_loop_quit(a->loop); + g_main_loop_unref(a->loop); + a->loop = NULL; +} + +static void test_qmp_return_async(void) +{ + QmpReturnAsync a = { { 0, } , }; + QDict *args = qdict_new(); + QDict *req = qdict_new(); + + a.loop = g_main_loop_new(NULL, TRUE); + qmp_session_init(&a.session, &qmp_commands, + NULL, dispatch_return_async); + + qdict_put_str(args, "filename", "test-filename"); + qdict_put_str(req, "execute", "cmd-async"); + qdict_put(req, "arguments", args); + qmp_dispatch(&a.session, QOBJECT(req), false); + g_assert(a.loop); + + g_main_loop_run(a.loop); + g_assert(!a.loop); + + qmp_session_destroy(&a.session); + qobject_unref(req); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -407,6 +466,7 @@ int main(int argc, char **argv) g_test_add_func("/qmp/dealloc_types", test_dealloc_types); g_test_add_func("/qmp/dealloc_partial", test_dealloc_partial); g_test_add_func("/qmp/return_orderly", test_qmp_return_orderly); + g_test_add_func("/qmp/return_async", test_qmp_return_async); test_qmp_init_marshal(&qmp_commands); g_test_run(); From patchwork Fri Nov 8 15:01:12 2019 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: 11235081 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8CCA315AB for ; Fri, 8 Nov 2019 15:12:37 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 17F9D215EA for ; Fri, 8 Nov 2019 15:12:37 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="UauoBIlp" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 17F9D215EA Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:55976 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5wB-0006oP-NG for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:12:35 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:46566) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5of-00056k-GS for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:04:52 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5oe-00059L-5J for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:04:49 -0500 Received: from us-smtp-1.mimecast.com ([207.211.31.81]:24959 helo=us-smtp-delivery-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5od-00058c-W6 for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:04:48 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225487; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6Ew9vHmiWjfrl81VNZzip86x0hD9sFmj8JBBNQVLTHg=; b=UauoBIlpiIgKhWGGreQM2ll6+wEALljH7TtReKWnkmjCqUl7c2jsvz1QS5ewXVW2944Eqf T9cvmEOq1Yl+saZtN7K+bE5DbGqFYPEgVKsPUdeQa/P/sWbMo1l1xhp5A2oDVmqpH/72mH Aq7IoS4/YyIctkN9CBxBq8FaQxKOCHI= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-335-V8MqFVBvNz2em5aS0e8HwA-1; Fri, 08 Nov 2019 10:04:46 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 7FF441005500 for ; Fri, 8 Nov 2019 15:04:45 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 55E035C1BB; Fri, 8 Nov 2019 15:04:37 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 14/25] qmp: add qmp_return_is_cancelled() Date: Fri, 8 Nov 2019 19:01:12 +0400 Message-Id: <20191108150123.12213-15-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-MC-Unique: V8MqFVBvNz2em5aS0e8HwA-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 207.211.31.81 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" If the client is gone, and the session finished, no need to return. The async handler can use this information to avoid unnecessary work and exit earlier. Signed-off-by: Marc-André Lureau --- include/qapi/qmp/dispatch.h | 8 ++++++++ qapi/qmp-dispatch.c | 10 ++++++++++ tests/test-qmp-cmds.c | 39 ++++++++++++++++++++++++++++++++++++- 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h index 6aef0abc70..6673902e95 100644 --- a/include/qapi/qmp/dispatch.h +++ b/include/qapi/qmp/dispatch.h @@ -91,6 +91,14 @@ void qmp_return_free(QmpReturn *qret); void qmp_return(QmpReturn *qret, QObject *rsp); void qmp_return_error(QmpReturn *qret, Error *err); +/* + * @qmp_return_is_cancelled: + * + * Return true if the QmpReturn is cancelled, and free the QmpReturn + * in this case. + */ +bool qmp_return_is_cancelled(QmpReturn *qret); + void qmp_register_command(QmpCommandList *cmds, const char *name, QmpCommandFunc *fn, QmpCommandOptions options); void qmp_register_async_command(QmpCommandList *cmds, const char *name, diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index 85e99671a9..e5c1505b05 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -64,6 +64,16 @@ void qmp_return_free(QmpReturn *qret) } } +bool qmp_return_is_cancelled(QmpReturn *qret) +{ + if (!qret->session) { + qmp_return_free(qret); + return true; + } + + return false; +} + static void qmp_return_orderly(QmpReturn *qret) { QmpSession *session = qret->session; diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c index 75ef30f6ea..66ad8726fe 100644 --- a/tests/test-qmp-cmds.c +++ b/tests/test-qmp-cmds.c @@ -34,17 +34,29 @@ void qmp_cmd_success_response(Error **errp) { } +static GMainLoop *loop; + static gboolean cmd_async_idle(gpointer user_data) { QmpReturn *qret = user_data; - qmp_cmd_async_return(qret, g_new0(Empty2, 1)); + if (!qret->session) { + g_assert(qmp_return_is_cancelled(qret)); + g_main_loop_quit(loop); + g_main_loop_unref(loop); + loop = NULL; + } else { + qmp_cmd_async_return(qret, g_new0(Empty2, 1)); + } return G_SOURCE_REMOVE; } void qmp_cmd_async(const char *filename, QmpReturn *qret) { + if (g_str_equal(filename, "cancel")) { + qmp_session_destroy(qret->session); + } g_idle_add(cmd_async_idle, qret); } @@ -453,6 +465,30 @@ static void test_qmp_return_async(void) qobject_unref(req); } +static void test_qmp_return_async_cancel(void) +{ + QmpReturnAsync a = { { 0, }, }; + QDict *args = qdict_new(); + QDict *req = qdict_new(); + + a.loop = g_main_loop_new(NULL, TRUE); + qmp_session_init(&a.session, &qmp_commands, + NULL, dispatch_return_async); + + qdict_put_str(args, "filename", "cancel"); + qdict_put_str(req, "execute", "cmd-async"); + qdict_put(req, "arguments", args); + qmp_dispatch(&a.session, QOBJECT(req), false); + g_assert(a.loop); + + loop = a.loop; + g_main_loop_run(loop); + g_assert(!loop); + + qmp_session_destroy(&a.session); + qobject_unref(req); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -467,6 +503,7 @@ int main(int argc, char **argv) g_test_add_func("/qmp/dealloc_partial", test_dealloc_partial); g_test_add_func("/qmp/return_orderly", test_qmp_return_orderly); g_test_add_func("/qmp/return_async", test_qmp_return_async); + g_test_add_func("/qmp/return_async_cancel", test_qmp_return_async_cancel); test_qmp_init_marshal(&qmp_commands); g_test_run(); From patchwork Fri Nov 8 15:01:13 2019 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: 11235103 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D5A8D1599 for ; Fri, 8 Nov 2019 15:22:56 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id ACF2F2178F for ; Fri, 8 Nov 2019 15:22:56 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="FJj2794X" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org ACF2F2178F Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:56114 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT66B-00015t-Jo for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:22:55 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:46584) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5om-0005BY-U7 for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:04:58 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5ol-0005JN-HE for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:04:56 -0500 Received: from us-smtp-1.mimecast.com ([207.211.31.81]:36409 helo=us-smtp-delivery-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5ol-0005J8-DR for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:04:55 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225495; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Wc4ftlDRX01CUchMOTZsiibJ9hNVG/BrpUrzGO6rXso=; b=FJj2794XmAFpA7z4k6wgK8hDIKmmeKaeZ0e86mBQwcNdEZM10uoniG056tHhRVKx5gDl/Z gZ//M2EnWz5zLVEggo3gwX8wCTpv6W1Cl5O6VZkTJlCwxYUB+dATJiL3FFk+xhJbyAwoUV aUrMCVdWHS6gii4VrICl5EElDg04ig0= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-93-VLkaUK2BN22tSY0L_cdEWg-1; Fri, 08 Nov 2019 10:04:53 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id F2DB7477 for ; Fri, 8 Nov 2019 15:04:52 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 69CE15C1BB; Fri, 8 Nov 2019 15:04:51 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 15/25] console: add graphic_hw_update_done() Date: Fri, 8 Nov 2019 19:01:13 +0400 Message-Id: <20191108150123.12213-16-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-MC-Unique: VLkaUK2BN22tSY0L_cdEWg-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 207.211.31.81 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" Add a function to be called when a graphic update is done. Declare the QXL renderer as async: render_update_cookie_num counts the number of outstanding updates, and graphic_hw_update_done() is called when it reaches none. Signed-off-by: Marc-André Lureau Reviewed-by: Gerd Hoffmann --- hw/display/qxl-render.c | 9 +++++++-- hw/display/qxl.c | 1 + include/ui/console.h | 2 ++ ui/console.c | 9 +++++++++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c index f7fdc4901e..3ce2e57b8f 100644 --- a/hw/display/qxl-render.c +++ b/hw/display/qxl-render.c @@ -109,7 +109,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) qxl->guest_primary.surface.mem, MEMSLOT_GROUP_GUEST); if (!qxl->guest_primary.data) { - return; + goto end; } qxl_set_rect_to_surface(qxl, &qxl->dirty[0]); qxl->num_dirty_rects = 1; @@ -137,7 +137,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) } if (!qxl->guest_primary.data) { - return; + goto end; } for (i = 0; i < qxl->num_dirty_rects; i++) { if (qemu_spice_rect_is_empty(qxl->dirty+i)) { @@ -158,6 +158,11 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) qxl->dirty[i].bottom - qxl->dirty[i].top); } qxl->num_dirty_rects = 0; + +end: + if (qxl->render_update_cookie_num == 0) { + graphic_hw_update_done(qxl->ssd.dcl.con); + } } /* diff --git a/hw/display/qxl.c b/hw/display/qxl.c index cd7eb39d20..6d43b7433c 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -1181,6 +1181,7 @@ static const QXLInterface qxl_interface = { static const GraphicHwOps qxl_ops = { .gfx_update = qxl_hw_update, + .gfx_update_async = true, }; static void qxl_enter_vga_mode(PCIQXLDevice *d) diff --git a/include/ui/console.h b/include/ui/console.h index f981696848..281f9c145b 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -365,6 +365,7 @@ static inline void console_write_ch(console_ch_t *dest, uint32_t ch) typedef struct GraphicHwOps { void (*invalidate)(void *opaque); void (*gfx_update)(void *opaque); + bool gfx_update_async; /* if true, calls graphic_hw_update_done() */ void (*text_update)(void *opaque, console_ch_t *text); void (*update_interval)(void *opaque, uint64_t interval); int (*ui_info)(void *opaque, uint32_t head, QemuUIInfo *info); @@ -380,6 +381,7 @@ void graphic_console_set_hwops(QemuConsole *con, void graphic_console_close(QemuConsole *con); void graphic_hw_update(QemuConsole *con); +void graphic_hw_update_done(QemuConsole *con); void graphic_hw_invalidate(QemuConsole *con); void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata); void graphic_hw_gl_block(QemuConsole *con, bool block); diff --git a/ui/console.c b/ui/console.c index 82d1ddac9c..3c941528d2 100644 --- a/ui/console.c +++ b/ui/console.c @@ -259,13 +259,22 @@ static void gui_setup_refresh(DisplayState *ds) ds->have_text = have_text; } +void graphic_hw_update_done(QemuConsole *con) +{ +} + void graphic_hw_update(QemuConsole *con) { + bool async = false; if (!con) { con = active_console; } if (con && con->hw_ops->gfx_update) { con->hw_ops->gfx_update(con->hw); + async = con->hw_ops->gfx_update_async; + } + if (!async) { + graphic_hw_update_done(con); } } From patchwork Fri Nov 8 15:01:14 2019 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: 11235115 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 355501709 for ; Fri, 8 Nov 2019 15:25:33 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 0CCAB2178F for ; Fri, 8 Nov 2019 15:25:32 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="LiERhUNp" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 0CCAB2178F Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:56138 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT68h-0003qH-UX for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:25:31 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:46646) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5p6-0005dX-3Q for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:05:17 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5p3-0005Wc-Of for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:05:15 -0500 Received: from us-smtp-1.mimecast.com ([205.139.110.61]:33575 helo=us-smtp-delivery-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5p3-0005VT-Kh for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:05:13 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225510; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=K6atlegt2pHhl2BHFOIZn9sIb4MIPYLA7+KTpFuvx0s=; b=LiERhUNpgbhsIzkKg6NiTZp5sApI/i8leO+DWdAeLBqJ6wpWDsYxnGqDvFqt6vo5nGWCq3 42i5crvNLMdJ/wIfEIX6LXTuTefqKj7PS/1Ga95V4M5gfbqdHRmoZ98+CjoT2Mm7R21oOU ugwTEbcoEPEqz3xd2GRnc/hsgW688CQ= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-24-bUcHVWTCMxmOc7_-1CU6-g-1; Fri, 08 Nov 2019 10:05:09 -0500 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id D45D0107ACC4 for ; Fri, 8 Nov 2019 15:05:08 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 2A538277B6; Fri, 8 Nov 2019 15:04:57 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 16/25] ppm-save: pass opened fd Date: Fri, 8 Nov 2019 19:01:14 +0400 Message-Id: <20191108150123.12213-17-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 X-MC-Unique: bUcHVWTCMxmOc7_-1CU6-g-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 205.139.110.61 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" This will allow to pre-open the file before running the async finish handler and avoid potential monitor fdset races. Signed-off-by: Marc-André Lureau --- ui/console.c | 45 ++++++++++++++++++++++----------------------- ui/trace-events | 2 +- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/ui/console.c b/ui/console.c index 3c941528d2..77d62fe76d 100644 --- a/ui/console.c +++ b/ui/console.c @@ -193,6 +193,7 @@ static void dpy_refresh(DisplayState *s); static DisplayState *get_alloc_displaystate(void); static void text_console_update_cursor_timer(void); static void text_console_update_cursor(void *opaque); +static bool ppm_save(int fd, DisplaySurface *ds, Error **errp); static void gui_update(void *opaque) { @@ -308,29 +309,22 @@ void graphic_hw_invalidate(QemuConsole *con) } } -static void ppm_save(const char *filename, DisplaySurface *ds, - Error **errp) +static bool ppm_save(int fd, DisplaySurface *ds, Error **errp) { int width = pixman_image_get_width(ds->image); int height = pixman_image_get_height(ds->image); - int fd; FILE *f; int y; int ret; pixman_image_t *linebuf; + bool success = false; - trace_ppm_save(filename, ds); - fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); - if (fd == -1) { - error_setg(errp, "failed to open file '%s': %s", filename, - strerror(errno)); - return; - } + trace_ppm_save(fd, ds); f = fdopen(fd, "wb"); ret = fprintf(f, "P6\n%d %d\n%d\n", width, height, 255); if (ret < 0) { linebuf = NULL; - goto write_err; + goto end; } linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width); for (y = 0; y < height; y++) { @@ -339,21 +333,16 @@ static void ppm_save(const char *filename, DisplaySurface *ds, ret = fwrite(pixman_image_get_data(linebuf), 1, pixman_image_get_stride(linebuf), f); (void)ret; - if (ferror(f)) { - goto write_err; - } + success = !ferror(f); } -out: +end: + if (!success) { + error_setg(errp, "failed to write to PPM file: %s", strerror(errno)); + } qemu_pixman_image_unref(linebuf); fclose(f); - return; - -write_err: - error_setg(errp, "failed to write to file '%s': %s", filename, - strerror(errno)); - unlink(filename); - goto out; + return success; } void qmp_screendump(const char *filename, bool has_device, const char *device, @@ -361,6 +350,7 @@ void qmp_screendump(const char *filename, bool has_device, const char *device, { QemuConsole *con; DisplaySurface *surface; + int fd; if (has_device) { con = qemu_console_lookup_by_device_name(device, has_head ? head : 0, @@ -387,7 +377,16 @@ void qmp_screendump(const char *filename, bool has_device, const char *device, return; } - ppm_save(filename, surface, errp); + fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + if (fd == -1) { + error_setg(errp, "failed to open file '%s': %s", filename, + strerror(errno)); + return; + } + + if (!ppm_save(fd, surface, errp)) { + unlink(filename); + } } void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata) diff --git a/ui/trace-events b/ui/trace-events index 63de72a798..0dcda393c1 100644 --- a/ui/trace-events +++ b/ui/trace-events @@ -15,7 +15,7 @@ displaysurface_create_pixman(void *display_surface) "surface=%p" displaysurface_free(void *display_surface) "surface=%p" displaychangelistener_register(void *dcl, const char *name) "%p [ %s ]" displaychangelistener_unregister(void *dcl, const char *name) "%p [ %s ]" -ppm_save(const char *filename, void *display_surface) "%s surface=%p" +ppm_save(int fd, void *display_surface) "fd=%d surface=%p" # gtk.c # gtk-gl-area.c From patchwork Fri Nov 8 15:01:15 2019 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: 11235085 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B4B1F1390 for ; Fri, 8 Nov 2019 15:13:32 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 8CA82215EA for ; Fri, 8 Nov 2019 15:13:32 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="eYLUWb2r" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 8CA82215EA Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:55982 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5x5-0007zQ-9B for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:13:31 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:46693) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5pK-00061O-34 for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:05:31 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5pF-0005kL-62 for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:05:29 -0500 Received: from us-smtp-2.mimecast.com ([205.139.110.61]:37980 helo=us-smtp-delivery-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5pF-0005jz-2A for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:05:25 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225524; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=AUi6QEZalbLTxvUCWZJyEZQMUqLH8rpUCT9b1rwUQl8=; b=eYLUWb2rY4PQMO62o7onDQoHlY862Np8pLfuVbzud6kq2j4Sl06b4lKyredPqv8oVZUjnU ME85kA3+4Oh8Upf0H0MOC824MvihVX0Y6TCwgd8P1FJjQ7G6y+tK3K9KMKMRrAiLlwpsZO N7N6ZxuCNerORhwLy5JKiBAhx/6Yq5E= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-260-pTyYSquwOQqf7DzP_5NEXw-1; Fri, 08 Nov 2019 10:05:23 -0500 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 3052B477 for ; Fri, 8 Nov 2019 15:05:22 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 32E81600C9; Fri, 8 Nov 2019 15:05:13 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 17/25] ui: add pixman image g_autoptr support Date: Fri, 8 Nov 2019 19:01:15 +0400 Message-Id: <20191108150123.12213-18-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-MC-Unique: pTyYSquwOQqf7DzP_5NEXw-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 205.139.110.61 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: Marc-André Lureau --- include/ui/qemu-pixman.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/ui/qemu-pixman.h b/include/ui/qemu-pixman.h index 0668109305..3b7cf70157 100644 --- a/include/ui/qemu-pixman.h +++ b/include/ui/qemu-pixman.h @@ -90,4 +90,6 @@ void qemu_pixman_glyph_render(pixman_image_t *glyph, pixman_color_t *bgcol, int x, int y, int cw, int ch); +G_DEFINE_AUTOPTR_CLEANUP_FUNC(pixman_image_t, qemu_pixman_image_unref) + #endif /* QEMU_PIXMAN_H */ From patchwork Fri Nov 8 15:01:16 2019 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: 11235093 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 76C3A1709 for ; Fri, 8 Nov 2019 15:17:07 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 4AEC3206C3 for ; Fri, 8 Nov 2019 15:17:07 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="h4QBm4PQ" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4AEC3206C3 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:56028 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT60X-0003EH-NU for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:17:05 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:46720) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5pR-0006Cg-LH for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:05:38 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5pQ-0005xT-Me for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:05:37 -0500 Received: from us-smtp-2.mimecast.com ([205.139.110.61]:41901 helo=us-smtp-delivery-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5pQ-0005wD-Iq for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:05:36 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225536; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=i/jhfPVbaw9zN74ATSitQu5mKIuSj4RbYiPEOhbuIgk=; b=h4QBm4PQ4oHnHvWWjC3E1hdOuRJPur98hg8b6i8H1SN++V9nkmNzHFdxujwWsPCUJvdsup 8eKnMgSWress1GaNC9w4hTW01oONjEEWmkdVUseFkCya2yZRfOIIm2up6qHSUorOjvrzTm +dKIfUCStIz/pSDMgXYAnVatE4/6Up4= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-350-2x3jsTa_OLCb6WVECiCvHQ-1; Fri, 08 Nov 2019 10:05:34 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id F268A107ACC4 for ; Fri, 8 Nov 2019 15:05:33 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 6E1B66084E; Fri, 8 Nov 2019 15:05:26 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 18/25] object: add g_autoptr support Date: Fri, 8 Nov 2019 19:01:16 +0400 Message-Id: <20191108150123.12213-19-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-MC-Unique: 2x3jsTa_OLCb6WVECiCvHQ-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 205.139.110.61 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: Marc-André Lureau --- include/qom/object.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/qom/object.h b/include/qom/object.h index 128d00c77f..f96a44be64 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1747,4 +1747,7 @@ Object *container_get(Object *root, const char *path); * Returns the instance_size of the given @typename. */ size_t object_type_get_instance_size(const char *typename); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(Object, object_unref) + #endif From patchwork Fri Nov 8 15:01:17 2019 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: 11235089 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7AB901709 for ; Fri, 8 Nov 2019 15:15:35 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 51F95215EA for ; Fri, 8 Nov 2019 15:15:35 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="EermZ3D4" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 51F95215EA Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:56014 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5z4-0001tU-0z for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:15:34 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:46792) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5pm-0006mC-3n for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:05:59 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5pj-0006M2-Ts for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:05:58 -0500 Received: from us-smtp-delivery-1.mimecast.com ([205.139.110.120]:27781 helo=us-smtp-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5pj-0006Ld-Q1 for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:05:55 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225555; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=V/mcHvKX7InUGUgT0KSXWZlTMQTnyJjgwdgTbknSH9s=; b=EermZ3D4Jz5xl9pUoGmCJmbvNdlG2Z09tAYt8paKJej3kqghZooKD1pCOlQdQxvBQtGtM2 1+bo23j37M7KrVx2iykm1imivNUa9es6QvuAx69PHtmI9qkfrG6pw6Mi1Q2BHSkF77rGUS swnrfuZk80FGq2qjkyB7+mwy+PrcS3M= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-28-wHajOuMYMjS7RgWHsoVTeA-1; Fri, 08 Nov 2019 10:05:54 -0500 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 485B61005500 for ; Fri, 8 Nov 2019 15:05:53 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id ED49D600CA; Fri, 8 Nov 2019 15:05:40 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 19/25] screendump: replace FILE with QIOChannel and fix close()/qemu_close() Date: Fri, 8 Nov 2019 19:01:17 +0400 Message-Id: <20191108150123.12213-20-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-MC-Unique: wHajOuMYMjS7RgWHsoVTeA-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 205.139.110.120 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" The file opened for ppm_save() may be a /dev/fdset, in which case a dup fd is added to the fdset. It should be removed by calling qemu_close(), instead of the implicit close() on fclose(). I don't see a convenient way to solve that with stdio streams, so I switched the code to QIOChannel which uses qemu_close(). Signed-off-by: Marc-André Lureau --- ui/console.c | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/ui/console.c b/ui/console.c index 77d62fe76d..587edf4ed4 100644 --- a/ui/console.c +++ b/ui/console.c @@ -33,6 +33,7 @@ #include "chardev/char-fe.h" #include "trace.h" #include "exec/memory.h" +#include "io/channel-file.h" #define DEFAULT_BACKSCROLL 512 #define CONSOLE_CURSOR_PERIOD 500 @@ -313,36 +314,31 @@ static bool ppm_save(int fd, DisplaySurface *ds, Error **errp) { int width = pixman_image_get_width(ds->image); int height = pixman_image_get_height(ds->image); - FILE *f; + g_autoptr(Object) ioc = OBJECT(qio_channel_file_new_fd(fd)); + g_autofree char *header = NULL; + g_autoptr(pixman_image_t) linebuf = NULL; + g_autoptr(GError) error = NULL; int y; - int ret; - pixman_image_t *linebuf; - bool success = false; trace_ppm_save(fd, ds); - f = fdopen(fd, "wb"); - ret = fprintf(f, "P6\n%d %d\n%d\n", width, height, 255); - if (ret < 0) { - linebuf = NULL; - goto end; + + header = g_strdup_printf("P6\n%d %d\n%d\n", width, height, 255); + if (qio_channel_write_all(QIO_CHANNEL(ioc), + header, strlen(header), errp) < 0) { + return false; } + linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width); for (y = 0; y < height; y++) { qemu_pixman_linebuf_fill(linebuf, ds->image, width, 0, y); - clearerr(f); - ret = fwrite(pixman_image_get_data(linebuf), 1, - pixman_image_get_stride(linebuf), f); - (void)ret; - success = !ferror(f); + if (qio_channel_write_all(QIO_CHANNEL(ioc), + (char *)pixman_image_get_data(linebuf), + pixman_image_get_stride(linebuf), errp) < 0) { + return false; + } } -end: - if (!success) { - error_setg(errp, "failed to write to PPM file: %s", strerror(errno)); - } - qemu_pixman_image_unref(linebuf); - fclose(f); - return success; + return true; } void qmp_screendump(const char *filename, bool has_device, const char *device, From patchwork Fri Nov 8 15:01:18 2019 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: 11235143 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6A6531599 for ; Fri, 8 Nov 2019 15:27:31 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 3981621882 for ; Fri, 8 Nov 2019 15:27:31 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="P0SYLfkJ" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 3981621882 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:56164 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT6Ab-0006Sf-Vx for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:27:30 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:46894) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5pz-00077R-UQ for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:06:12 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5py-0006Up-Ov for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:06:11 -0500 Received: from us-smtp-1.mimecast.com ([207.211.31.81]:35846 helo=us-smtp-delivery-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5py-0006Ul-LU for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:06:10 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225570; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=p8tsVTUfoEfZv9VhDPcAAEq3rQMQDEoIiccaTGADpU8=; b=P0SYLfkJGVGCb11QTJjMqlUAk20H+WQ5mqs3rRZmk/zucwuAvpgmMnkM1I+T0e4bcj9o+e VzYnts2khSCvYJi8K/ae7bGbj1rKfJaN9Pg8bSv/DbBsgMzb7B5avj8H6BL+nAv2LB/qRP tP7sD80B4N2Q4pc8eLmS4ZWpJDdnY7o= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-203-_sIIgBRpN5GmaQELGwyHUQ-1; Fri, 08 Nov 2019 10:06:07 -0500 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 018C3800C72 for ; Fri, 8 Nov 2019 15:06:07 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 62F8350; Fri, 8 Nov 2019 15:05:58 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 20/25] osdep: add qemu_unlink() Date: Fri, 8 Nov 2019 19:01:18 +0400 Message-Id: <20191108150123.12213-21-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 X-MC-Unique: _sIIgBRpN5GmaQELGwyHUQ-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 207.211.31.81 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" Add a helper function to match qemu_open() which may return files under the /dev/fdset prefix. Those shouldn't be removed, since it's only a qemu namespace. Signed-off-by: Marc-André Lureau --- include/qemu/osdep.h | 1 + util/osdep.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 0f97d68586..9bd3dcfd13 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -462,6 +462,7 @@ int qemu_mprotect_none(void *addr, size_t size); int qemu_open(const char *name, int flags, ...); int qemu_close(int fd); +int qemu_unlink(const char *name); #ifndef _WIN32 int qemu_dup(int fd); #endif diff --git a/util/osdep.c b/util/osdep.c index 3f04326040..f7d06050f7 100644 --- a/util/osdep.c +++ b/util/osdep.c @@ -370,6 +370,21 @@ int qemu_close(int fd) return close(fd); } +/* + * Delete a file from the filesystem, unless the filename is /dev/fdset/... + * + * Returns: On success, zero is returned. On error, -1 is returned, + * and errno is set appropriately. + */ +int qemu_unlink(const char *name) +{ + if (g_str_has_prefix(name, "/dev/fdset/")) { + return 0; + } + + return unlink(name); +} + /* * A variant of write(2) which handles partial write. * From patchwork Fri Nov 8 15:01:19 2019 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: 11235087 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BEF1E1390 for ; Fri, 8 Nov 2019 15:14:02 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9610D215EA for ; Fri, 8 Nov 2019 15:14:02 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Zbua80ZV" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9610D215EA Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:55988 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5xZ-0000Lb-Gs for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:14:01 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:46945) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5qB-0007O2-09 for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:06:27 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5qA-0006jT-1H for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:06:22 -0500 Received: from us-smtp-2.mimecast.com ([205.139.110.61]:47117 helo=us-smtp-delivery-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5q9-0006j1-Tj for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:06:21 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225581; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=sTE5AxWhHFArGW+tZpivPFPM3d7d8XOs49LHe2Qq4Fk=; b=Zbua80ZVjo98chTLG2HFbjCz1CzZmxhqRDL5Hkzo7LVEuHYL2kWJlPJO0LtRavkAacHBLo e9KCzMZkcPSq8gnedllgVaPztZRoLLrPtPjgJbOGQbPwesVj+K5ciHOK5QG7wkjDWam+f7 XZbRWV3lqIecAzsUNpNHFZt32UZ1tu8= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-230-p0XitW--PeaYvSuDLBzJ1g-1; Fri, 08 Nov 2019 10:06:20 -0500 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 4FE31800C72 for ; Fri, 8 Nov 2019 15:06:19 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7BFB860BE2; Fri, 8 Nov 2019 15:06:12 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 21/25] screendump: use qemu_unlink() Date: Fri, 8 Nov 2019 19:01:19 +0400 Message-Id: <20191108150123.12213-22-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-MC-Unique: p0XitW--PeaYvSuDLBzJ1g-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 205.139.110.61 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" Don't attempt to remove /dev/fdset files. Signed-off-by: Marc-André Lureau --- ui/console.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/console.c b/ui/console.c index 587edf4ed4..e6ac462aa0 100644 --- a/ui/console.c +++ b/ui/console.c @@ -381,7 +381,7 @@ void qmp_screendump(const char *filename, bool has_device, const char *device, } if (!ppm_save(fd, surface, errp)) { - unlink(filename); + qemu_unlink(filename); } } From patchwork Fri Nov 8 15:01:20 2019 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: 11235095 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 831B91390 for ; Fri, 8 Nov 2019 15:18:16 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 5A67C2178F for ; Fri, 8 Nov 2019 15:18:16 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="LhUTyHuJ" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 5A67C2178F Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:56046 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT61e-000494-WC for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:18:15 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:46992) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5qL-0007hS-NL for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:06:35 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5qK-0006zf-3C for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:06:33 -0500 Received: from us-smtp-delivery-1.mimecast.com ([207.211.31.120]:24198 helo=us-smtp-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5qJ-0006yP-VW for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:06:32 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225591; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6a3WqY1R8aTdRQZwRQ6BSdOmt8hmHjf7TQvvlhpK+xA=; b=LhUTyHuJtQUObRWcGJRd7ecCjw/nLERc7P4KV3n3z0TEZkWIzmWz+XUWbWCUDrO0Ghs8v8 EFLnp/3hB04V7bXgsnnLhSlG1sRmI+a++WmY2f95YTmGwNaCWgg/Mxlb85XqklvnaJe0EH fSXG2p8wG2LAgjdaeKWP9Xca7JlJmRw= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-257-7p8TTBpQOJ2NQBvL8aCKOg-1; Fri, 08 Nov 2019 10:06:30 -0500 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 67A89180496F for ; Fri, 8 Nov 2019 15:06:29 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 288265D6AE; Fri, 8 Nov 2019 15:06:24 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 22/25] console: make screendump asynchronous Date: Fri, 8 Nov 2019 19:01:20 +0400 Message-Id: <20191108150123.12213-23-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-MC-Unique: 7p8TTBpQOJ2NQBvL8aCKOg-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 207.211.31.120 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" Make screendump asynchronous to provide correct screendumps. For now, HMP doesn't have async support, so it has to remain synchronous and potentially incorrect to avoid races (following patches will add HMP asynchronous commands) Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1230527 Signed-off-by: Marc-André Lureau --- include/ui/console.h | 3 ++ monitor/hmp-cmds.c | 2 +- qapi/ui.json | 3 +- ui/console.c | 117 +++++++++++++++++++++++++++++++++++++++---- 4 files changed, 113 insertions(+), 12 deletions(-) diff --git a/include/ui/console.h b/include/ui/console.h index 281f9c145b..a1935557cc 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -74,6 +74,9 @@ typedef struct MouseTransformInfo { } MouseTransformInfo; void hmp_mouse_set(Monitor *mon, const QDict *qdict); +void hmp_screendump_sync(const char *filename, + bool has_device, const char *device, + bool has_head, int64_t head, Error **errp); /* keysym is a unicode code except for special keys (see QEMU_KEY_xxx constants) */ diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index b2551c16d1..c52e78fedf 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -2308,7 +2308,7 @@ void hmp_screendump(Monitor *mon, const QDict *qdict) int64_t head = qdict_get_try_int(qdict, "head", 0); Error *err = NULL; - qmp_screendump(filename, id != NULL, id, id != NULL, head, &err); + hmp_screendump_sync(filename, id != NULL, id, id != NULL, head, &err); hmp_handle_error(mon, &err); } diff --git a/qapi/ui.json b/qapi/ui.json index e04525d8b4..148ae4c062 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -96,7 +96,8 @@ # ## { 'command': 'screendump', - 'data': {'filename': 'str', '*device': 'str', '*head': 'int'} } + 'data': {'filename': 'str', '*device': 'str', '*head': 'int'}, + 'async': true } ## # == Spice diff --git a/ui/console.c b/ui/console.c index e6ac462aa0..fd87605b7c 100644 --- a/ui/console.c +++ b/ui/console.c @@ -34,6 +34,7 @@ #include "trace.h" #include "exec/memory.h" #include "io/channel-file.h" +#include "monitor/monitor.h" #define DEFAULT_BACKSCROLL 512 #define CONSOLE_CURSOR_PERIOD 500 @@ -118,6 +119,13 @@ typedef enum { TEXT_CONSOLE_FIXED_SIZE } console_type_t; +struct qmp_screendump { + int fd; + gchar *filename; + QmpReturn *ret; + QLIST_ENTRY(qmp_screendump) link; +}; + struct QemuConsole { Object parent; @@ -168,6 +176,8 @@ struct QemuConsole { uint8_t out_fifo_buf[16]; QEMUTimer *kbd_timer; + QLIST_HEAD(, qmp_screendump) qmp_screendumps; + QTAILQ_ENTRY(QemuConsole) next; }; @@ -261,8 +271,51 @@ static void gui_setup_refresh(DisplayState *ds) ds->have_text = have_text; } +static void qmp_screendump_finish(QemuConsole *con, struct qmp_screendump *dump) +{ + Error *err = NULL; + DisplaySurface *surface; + + if (qmp_return_is_cancelled(dump->ret)) { + goto cleanup; + } + + surface = qemu_console_surface(con); + if (!surface) { + error_setg(&err, "no surface"); + } else { + /* + * FIXME: async save with coroutine? it would have to copy or + * lock the surface. + */ + if (!ppm_save(dump->fd, surface, &err)) { + qemu_unlink(dump->filename); + } + dump->fd = -1; + } + + if (err) { + qmp_return_error(dump->ret, err); + } else { + qmp_screendump_return(dump->ret); + } + +cleanup: + if (dump->fd != -1) { + qemu_close(dump->fd); + } + g_free(dump->filename); + QLIST_REMOVE(dump, link); + g_free(dump); +} + void graphic_hw_update_done(QemuConsole *con) { + struct qmp_screendump *dump, *next; + + QLIST_FOREACH_SAFE(dump, &con->qmp_screendumps, link, next) { + qmp_screendump_finish(con, dump); + } } void graphic_hw_update(QemuConsole *con) @@ -341,31 +394,42 @@ static bool ppm_save(int fd, DisplaySurface *ds, Error **errp) return true; } -void qmp_screendump(const char *filename, bool has_device, const char *device, - bool has_head, int64_t head, Error **errp) + +static QemuConsole *get_console(bool has_device, const char *device, + bool has_head, int64_t head, Error **errp) { - QemuConsole *con; - DisplaySurface *surface; - int fd; + QemuConsole *con = NULL; if (has_device) { con = qemu_console_lookup_by_device_name(device, has_head ? head : 0, errp); - if (!con) { - return; - } } else { if (has_head) { error_setg(errp, "'head' must be specified together with 'device'"); - return; + return NULL; } con = qemu_console_lookup_by_index(0); if (!con) { error_setg(errp, "There is no console to take a screendump from"); - return; } } + return con; +} + +void hmp_screendump_sync(const char *filename, + bool has_device, const char *device, + bool has_head, int64_t head, Error **errp) +{ + DisplaySurface *surface; + QemuConsole *con = get_console(has_device, device, has_head, head, errp); + int fd; + + if (!con) { + return; + } + /* This may not complete the drawing with Spice, you may have + * glitches or outdated dumps, use qmp instead! */ graphic_hw_update(con); surface = qemu_console_surface(con); if (!surface) { @@ -385,6 +449,38 @@ void qmp_screendump(const char *filename, bool has_device, const char *device, } } +void qmp_screendump(const char *filename, + bool has_device, const char *device, + bool has_head, int64_t head, + QmpReturn *qret) +{ + Error *err = NULL; + struct qmp_screendump *dump = NULL; + QemuConsole *con = get_console(has_device, device, has_head, head, &err); + int fd; + + if (!con) { + qmp_return_error(qret, err); + return; + } + + fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + if (fd == -1) { + error_setg(&err, "failed to open file '%s': %s", + filename, strerror(errno)); + qmp_return_error(qret, err); + return; + } + + dump = g_new(struct qmp_screendump, 1); + dump->fd = fd; + dump->filename = g_strdup(filename); + dump->ret = qret; + QLIST_INSERT_HEAD(&con->qmp_screendumps, dump, link); + + graphic_hw_update(con); +} + void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata) { if (!con) { @@ -1295,6 +1391,7 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type, obj = object_new(TYPE_QEMU_CONSOLE); s = QEMU_CONSOLE(obj); s->head = head; + QLIST_INIT(&s->qmp_screendumps); object_property_add_link(obj, "device", TYPE_DEVICE, (Object **)&s->device, object_property_allow_set_link, From patchwork Fri Nov 8 15:01:21 2019 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: 11235101 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 73A571599 for ; Fri, 8 Nov 2019 15:21:25 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 3E9BE21882 for ; Fri, 8 Nov 2019 15:21:25 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="RZg0z+49" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 3E9BE21882 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:56094 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT64i-0007mF-A5 for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:21:24 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:47049) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5qY-00084N-Lj for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:06:49 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5qX-0007KH-Ja for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:06:46 -0500 Received: from us-smtp-delivery-1.mimecast.com ([205.139.110.120]:58922 helo=us-smtp-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5qX-0007K8-G3 for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:06:45 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225605; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=8COIJESeTAOSHPsFPA7tx+V+NQP3cSzWSMBW9wKxKRE=; b=RZg0z+49IchjJ332ztKvaZcLctcWL5rJSyUKvaz73uNdUA0AbDa46UNrI+Fq9pqBkAMxgM /3aDtCGTQ83NnlkBjUA9LUBc0V4hysAbps+WLB743mS7WP3Hw13MkB+HUcYtMkY1AvKISS Bc6e0Yz8nPqCCeou2D820VjKv9bgGOY= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-220-B34aZhinPSCwpmVUNoN-pw-1; Fri, 08 Nov 2019 10:06:43 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id B0C44107ACC4 for ; Fri, 8 Nov 2019 15:06:42 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 423AD6084E; Fri, 8 Nov 2019 15:06:35 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 23/25] monitor: start making qmp_human_monitor_command() asynchronous Date: Fri, 8 Nov 2019 19:01:21 +0400 Message-Id: <20191108150123.12213-24-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-MC-Unique: B34aZhinPSCwpmVUNoN-pw-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 205.139.110.120 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" This prepares the work for HMP commands to be asynchronous. Start making QMP human-monitor-command asynchronous, although QmpReturn is used synchronously on error or after handle_hmp_command(). Signed-off-by: Marc-André Lureau --- monitor/misc.c | 14 ++++++++------ qapi/misc.json | 3 ++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/monitor/misc.c b/monitor/misc.c index bb33ca73cf..3617f855f5 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -115,8 +115,8 @@ static QLIST_HEAD(, MonFdset) mon_fdsets; static HMPCommand hmp_info_cmds[]; -char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index, - int64_t cpu_index, Error **errp) +void qmp_human_monitor_command(const char *command_line, bool has_cpu_index, + int64_t cpu_index, QmpReturn *qret) { char *output = NULL; Monitor *old_mon; @@ -130,15 +130,15 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index, if (has_cpu_index) { int ret = monitor_set_cpu(cpu_index); if (ret < 0) { - cur_mon = old_mon; - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cpu-index", + Error *err = NULL; + error_setg(&err, QERR_INVALID_PARAMETER_VALUE, "cpu-index", "a CPU number"); + qmp_return_error(qret, err); goto out; } } handle_hmp_command(&hmp, command_line); - cur_mon = old_mon; qemu_mutex_lock(&hmp.common.mon_lock); if (qstring_get_length(hmp.common.outbuf) > 0) { @@ -148,9 +148,11 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index, } qemu_mutex_unlock(&hmp.common.mon_lock); + qmp_human_monitor_command_return(qret, output); + out: + cur_mon = old_mon; monitor_data_destroy(&hmp.common); - return output; } /** diff --git a/qapi/misc.json b/qapi/misc.json index 33b94e3589..15a8bc0d0d 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -1054,7 +1054,8 @@ { 'command': 'human-monitor-command', 'data': {'command-line': 'str', '*cpu-index': 'int'}, 'returns': 'str', - 'features': [ 'savevm-monitor-nodes' ] } + 'features': [ 'savevm-monitor-nodes' ], + 'async': true } ## # @change: From patchwork Fri Nov 8 15:01:22 2019 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: 11235107 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 57A421709 for ; Fri, 8 Nov 2019 15:24:00 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 2F5B221882 for ; Fri, 8 Nov 2019 15:24:00 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="I9oNEHeh" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 2F5B221882 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:56120 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT67D-00024K-8L for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:23:59 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:47069) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5qg-0008El-9g for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:06:55 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5qe-0007Oy-F0 for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:06:54 -0500 Received: from us-smtp-delivery-1.mimecast.com ([207.211.31.120]:42268 helo=us-smtp-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5qe-0007Nt-BE for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:06:52 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225612; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=t5+8G8AEV1Ea0pzG+NwjP+QZF/+PogJ5CNni0zkdM0g=; b=I9oNEHehXw8dGHMg45a3KK6dq6L+A6SQ3GCpVjuIHWNMp/Yao1722hImUpfO7jawE1d0Zz HfmM+54HflsgMmug0aLIup3DOJvbCcVUTFa6syAmIn7xCaqRJGdESmCyVa2TAVGkwN9fXK jdUlnK+Y+9vYwA89uaa5mU3nm3Y16ic= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-255-WcjvzvK1NqKIrJr1yuL7gQ-1; Fri, 08 Nov 2019 10:06:50 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 04D72180496F for ; Fri, 8 Nov 2019 15:06:50 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8F0046084E; Fri, 8 Nov 2019 15:06:47 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 24/25] monitor: teach HMP about asynchronous commands Date: Fri, 8 Nov 2019 19:01:22 +0400 Message-Id: <20191108150123.12213-25-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-MC-Unique: WcjvzvK1NqKIrJr1yuL7gQ-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 207.211.31.120 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" Similar to how we handle both synchronous and asynchronous commands in QMP, HMP gains a new async_cmd() that will allow the command to complete asynchronously. For interactive reasons, and command ordering, the HMP monitor is suspended until the asynchronous command completes. It is expected that HMP async commands will be implemented re-using QMP async commands counterparts, so it reuses the QmpSession/QmpReturn for context handling (instead of introducing HmpSession/HmpReturn and having to convert from one to the other as we call QMP counterparts). hmp_dispatch_return_cb() will handle printing the result to the current monitor. It may have different ways to print the QmpReturn result to the current monitor. Currently, only error reporting is implemented. QMP human-monitor-command is modified to deal with an async HMP commands too. It creates a temporary session, and the return callback will return asynchronously to the original QMP command and destroy the temporary monitor when hmp->for_qmp_command is set. Signed-off-by: Marc-André Lureau --- monitor/hmp.c | 110 +++++++++++++++++++++++++++++++++++-- monitor/misc.c | 40 -------------- monitor/monitor-internal.h | 9 ++- 3 files changed, 113 insertions(+), 46 deletions(-) diff --git a/monitor/hmp.c b/monitor/hmp.c index 8942e28933..07f305141d 100644 --- a/monitor/hmp.c +++ b/monitor/hmp.c @@ -26,11 +26,15 @@ #include #include "monitor-internal.h" #include "qapi/error.h" +#include "qapi/qapi-commands-misc.h" +#include "qapi/qmp/qerror.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qnum.h" +#include "qapi/qmp/qstring.h" #include "qemu/config-file.h" #include "qemu/ctype.h" #include "qemu/cutils.h" +#include "qemu/error-report.h" #include "qemu/log.h" #include "qemu/option.h" #include "qemu/units.h" @@ -38,6 +42,8 @@ #include "sysemu/runstate.h" #include "trace.h" +static bool handle_hmp_command(MonitorHMP *mon, const char *cmdline); + static void monitor_command_cb(void *opaque, const char *cmdline, void *readline_opaque) { @@ -1056,7 +1062,7 @@ fail: return NULL; } -void handle_hmp_command(MonitorHMP *mon, const char *cmdline) +static bool handle_hmp_command(MonitorHMP *mon, const char *cmdline) { QDict *qdict; const HMPCommand *cmd; @@ -1066,7 +1072,7 @@ void handle_hmp_command(MonitorHMP *mon, const char *cmdline) cmd = monitor_parse_command(mon, cmdline, &cmdline, hmp_cmds); if (!cmd) { - return; + return false; } qdict = monitor_parse_arguments(&mon->common, &cmdline, cmd); @@ -1076,11 +1082,19 @@ void handle_hmp_command(MonitorHMP *mon, const char *cmdline) } monitor_printf(&mon->common, "Try \"help %.*s\" for more information\n", (int)(cmdline - cmd_start), cmd_start); - return; + return false; } - cmd->cmd(&mon->common, qdict); + if (cmd->async) { + QmpReturn *qret = qmp_return_new(&mon->qmp_session, NULL); + monitor_suspend(&mon->common); + cmd->async_cmd(&mon->common, qdict, qret); + } else { + cmd->cmd(&mon->common, qdict); + } qobject_unref(qdict); + + return cmd->async; } static void cmd_completion(MonitorHMP *mon, const char *name, const char *list) @@ -1395,6 +1409,59 @@ static void monitor_readline_flush(void *opaque) monitor_flush(&mon->common); } +static void free_hmp_monitor(void *opaque) +{ + MonitorHMP *hmp = opaque; + + qmp_session_destroy(&hmp->qmp_session); + monitor_data_destroy(&hmp->common); + g_free(hmp); +} + +static AioContext *monitor_get_aio_context(void) +{ + return iothread_get_aio_context(mon_iothread); +} + +static void qmp_human_monitor_command_finish(MonitorHMP *hmp, QmpReturn *qret) +{ + char *output; + + qemu_mutex_lock(&hmp->common.mon_lock); + if (qstring_get_length(hmp->common.outbuf) > 0) { + output = g_strdup(qstring_get_str(hmp->common.outbuf)); + } else { + output = g_strdup(""); + } + qemu_mutex_unlock(&hmp->common.mon_lock); + + qmp_human_monitor_command_return(qret, output); + + if (hmp->for_qmp_command) { + aio_bh_schedule_oneshot(monitor_get_aio_context(), + free_hmp_monitor, hmp); + } +} + +static void hmp_dispatch_return_cb(QmpSession *session, QDict *rsp) +{ + MonitorHMP *hmp = container_of(session, MonitorHMP, qmp_session); + QDict *err = qdict_get_qdict(rsp, "error"); + Monitor *old_mon = cur_mon; + + cur_mon = &hmp->common; + if (err) { + error_report("%s", qdict_get_str(err, "desc")); + } /* XXX: else, report depending on command */ + + if (hmp->for_qmp_command) { + qmp_human_monitor_command_finish(hmp, hmp->for_qmp_command); + } else { + monitor_resume(&hmp->common); + } + cur_mon = old_mon; +} + void monitor_init_hmp(Chardev *chr, bool use_readline) { MonitorHMP *mon = g_new0(MonitorHMP, 1); @@ -1411,7 +1478,42 @@ void monitor_init_hmp(Chardev *chr, bool use_readline) monitor_read_command(mon, 0); } + qmp_session_init(&mon->qmp_session, + NULL, NULL, hmp_dispatch_return_cb); qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read, monitor_read, monitor_event, NULL, &mon->common, NULL, true); monitor_list_append(&mon->common); } + +void qmp_human_monitor_command(const char *command_line, bool has_cpu_index, + int64_t cpu_index, QmpReturn *qret) +{ + Monitor *old_mon; + MonitorHMP *hmp = g_new0(MonitorHMP, 1); + + monitor_data_init(&hmp->common, false, true, false); + qmp_session_init(&hmp->qmp_session, NULL, NULL, hmp_dispatch_return_cb); + hmp->for_qmp_command = qret; + + old_mon = cur_mon; + cur_mon = &hmp->common; + + if (has_cpu_index) { + int ret = monitor_set_cpu(cpu_index); + if (ret < 0) { + Error *err = NULL; + error_setg(&err, QERR_INVALID_PARAMETER_VALUE, "cpu-index", + "a CPU number"); + qmp_return_error(qret, err); + free_hmp_monitor(hmp); + goto out; + } + } + + if (!handle_hmp_command(hmp, command_line)) { + qmp_human_monitor_command_finish(hmp, qret); + } + +out: + cur_mon = old_mon; +} diff --git a/monitor/misc.c b/monitor/misc.c index 3617f855f5..ed672db650 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -115,46 +115,6 @@ static QLIST_HEAD(, MonFdset) mon_fdsets; static HMPCommand hmp_info_cmds[]; -void qmp_human_monitor_command(const char *command_line, bool has_cpu_index, - int64_t cpu_index, QmpReturn *qret) -{ - char *output = NULL; - Monitor *old_mon; - MonitorHMP hmp = {}; - - monitor_data_init(&hmp.common, false, true, false); - - old_mon = cur_mon; - cur_mon = &hmp.common; - - if (has_cpu_index) { - int ret = monitor_set_cpu(cpu_index); - if (ret < 0) { - Error *err = NULL; - error_setg(&err, QERR_INVALID_PARAMETER_VALUE, "cpu-index", - "a CPU number"); - qmp_return_error(qret, err); - goto out; - } - } - - handle_hmp_command(&hmp, command_line); - - qemu_mutex_lock(&hmp.common.mon_lock); - if (qstring_get_length(hmp.common.outbuf) > 0) { - output = g_strdup(qstring_get_str(hmp.common.outbuf)); - } else { - output = g_strdup(""); - } - qemu_mutex_unlock(&hmp.common.mon_lock); - - qmp_human_monitor_command_return(qret, output); - -out: - cur_mon = old_mon; - monitor_data_destroy(&hmp.common); -} - /** * Is @name in the '|' separated list of names @list? */ diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h index b8994f896a..d13da7db31 100644 --- a/monitor/monitor-internal.h +++ b/monitor/monitor-internal.h @@ -72,7 +72,10 @@ typedef struct HMPCommand { const char *params; const char *help; const char *flags; /* p=preconfig */ - void (*cmd)(Monitor *mon, const QDict *qdict); + union { + void (*cmd)(Monitor *mon, const QDict *qdict); + void (*async_cmd)(Monitor *mon, const QDict *qdict, QmpReturn *qret); + }; /* * @sub_table is a list of 2nd level of commands. If it does not exist, * cmd should be used. If it exists, sub_table[?].cmd should be @@ -80,6 +83,7 @@ typedef struct HMPCommand { */ struct HMPCommand *sub_table; void (*command_completion)(ReadLineState *rs, int nb_args, const char *str); + bool async; } HMPCommand; struct Monitor { @@ -120,6 +124,8 @@ struct MonitorHMP { * These members can be safely accessed without locks. */ ReadLineState *rs; + QmpReturn *for_qmp_command; + QmpSession qmp_session; }; typedef struct { @@ -175,7 +181,6 @@ void monitor_qmp_bh_dispatcher(void *data); int get_monitor_def(int64_t *pval, const char *name); void help_cmd(Monitor *mon, const char *name); -void handle_hmp_command(MonitorHMP *mon, const char *cmdline); int hmp_compare_cmd(const char *name, const char *list); #endif From patchwork Fri Nov 8 15:01:23 2019 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: 11235117 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 0ACA51709 for ; Fri, 8 Nov 2019 15:26:03 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id D5DE32178F for ; Fri, 8 Nov 2019 15:26:02 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Xusmo5R3" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org D5DE32178F Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:56140 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT69B-0004fR-VW for patchwork-qemu-devel@patchwork.kernel.org; Fri, 08 Nov 2019 10:26:02 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:47173) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iT5qu-00006l-2n for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:07:09 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iT5qs-0007uw-SS for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:07:08 -0500 Received: from us-smtp-delivery-1.mimecast.com ([205.139.110.120]:44199 helo=us-smtp-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iT5qs-0007s1-O1 for qemu-devel@nongnu.org; Fri, 08 Nov 2019 10:07:06 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573225626; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=l8YNejVxznOcDAaMUcNNOGhdD0r56jyIWDDN7FE48fc=; b=Xusmo5R3odNFLvpu/KRKzM1NjbuJsSNJTcnNw6COH9tDVxEiM12RsEPOEw79hMg8ETMsXJ 1bj7KUyhqbaEUupgCgieTUt5DAr6uSM5Hmzu3awvQACuj5LyZZDXkIu5J3MVX5o5k+TvFx PuFYvChkWygVNbeC0Y2J5i6/hcn2IiQ= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-382-4HcH353HN_uQkdXD2rCBGQ-1; Fri, 08 Nov 2019 10:07:05 -0500 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 81724180496F for ; Fri, 8 Nov 2019 15:07:02 +0000 (UTC) Received: from localhost (ovpn-112-25.ams2.redhat.com [10.36.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4127C50; Fri, 8 Nov 2019 15:06:54 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Subject: [PATCH v6 25/25] hmp: call the asynchronous QMP screendump to fix outdated/glitches Date: Fri, 8 Nov 2019 19:01:23 +0400 Message-Id: <20191108150123.12213-26-marcandre.lureau@redhat.com> In-Reply-To: <20191108150123.12213-1-marcandre.lureau@redhat.com> References: <20191108150123.12213-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 X-MC-Unique: 4HcH353HN_uQkdXD2rCBGQ-1 X-Mimecast-Spam-Score: 0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 205.139.110.120 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , armbru@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" In order to fix the bad screendumps (same as rhbz#1230527), call into the asynchonous version of the QMP command. Signed-off-by: Marc-André Lureau --- hmp-commands.hx | 3 ++- include/ui/console.h | 5 ++--- monitor/hmp-cmds.c | 6 ++---- ui/console.c | 32 -------------------------------- 4 files changed, 6 insertions(+), 40 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index cfcc044ce4..82b9236deb 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -278,7 +278,8 @@ ETEXI .params = "filename [device [head]]", .help = "save screen from head 'head' of display device 'device' " "into PPM image 'filename'", - .cmd = hmp_screendump, + .async_cmd = hmp_screendump_async, + .async = true, }, STEXI diff --git a/include/ui/console.h b/include/ui/console.h index a1935557cc..d0a2a2066f 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -6,6 +6,7 @@ #include "qemu/notify.h" #include "qemu/error-report.h" #include "qapi/qapi-types-ui.h" +#include "qapi/qmp/dispatch.h" #ifdef CONFIG_OPENGL # include @@ -74,9 +75,7 @@ typedef struct MouseTransformInfo { } MouseTransformInfo; void hmp_mouse_set(Monitor *mon, const QDict *qdict); -void hmp_screendump_sync(const char *filename, - bool has_device, const char *device, - bool has_head, int64_t head, Error **errp); +void hmp_screendump_async(Monitor *mon, const QDict *qdict, QmpReturn *qret); /* keysym is a unicode code except for special keys (see QEMU_KEY_xxx constants) */ diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index c52e78fedf..93b061cf4f 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -2301,15 +2301,13 @@ err_out: goto out; } -void hmp_screendump(Monitor *mon, const QDict *qdict) +void hmp_screendump_async(Monitor *mon, const QDict *qdict, QmpReturn *qret) { const char *filename = qdict_get_str(qdict, "filename"); const char *id = qdict_get_try_str(qdict, "device"); int64_t head = qdict_get_try_int(qdict, "head", 0); - Error *err = NULL; - hmp_screendump_sync(filename, id != NULL, id, id != NULL, head, &err); - hmp_handle_error(mon, &err); + qmp_screendump(filename, id != NULL, id, id != NULL, head, qret); } void hmp_nbd_server_start(Monitor *mon, const QDict *qdict) diff --git a/ui/console.c b/ui/console.c index fd87605b7c..a6f8e34e61 100644 --- a/ui/console.c +++ b/ui/console.c @@ -417,38 +417,6 @@ static QemuConsole *get_console(bool has_device, const char *device, return con; } -void hmp_screendump_sync(const char *filename, - bool has_device, const char *device, - bool has_head, int64_t head, Error **errp) -{ - DisplaySurface *surface; - QemuConsole *con = get_console(has_device, device, has_head, head, errp); - int fd; - - if (!con) { - return; - } - /* This may not complete the drawing with Spice, you may have - * glitches or outdated dumps, use qmp instead! */ - graphic_hw_update(con); - surface = qemu_console_surface(con); - if (!surface) { - error_setg(errp, "no surface"); - return; - } - - fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); - if (fd == -1) { - error_setg(errp, "failed to open file '%s': %s", filename, - strerror(errno)); - return; - } - - if (!ppm_save(fd, surface, errp)) { - qemu_unlink(filename); - } -} - void qmp_screendump(const char *filename, bool has_device, const char *device, bool has_head, int64_t head,