qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Bandan Das <bsd@redhat.com>
To: Markus Armbruster <armbru@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>,
	qemu-devel@nongnu.org, Luiz Capitulino <lcapitulino@redhat.com>
Subject: Re: [Qemu-devel] [PATCH] monitor: suggest running "help" for command errors
Date: Fri, 15 May 2015 00:37:22 -0400	[thread overview]
Message-ID: <jpglhgqh2wt.fsf@redhat.com> (raw)
In-Reply-To: <874mnf7610.fsf@blackfin.pond.sub.org> (Markus Armbruster's message of "Thu, 14 May 2015 13:27:55 +0200")

Markus Armbruster <armbru@redhat.com> writes:

> Bandan Das <bsd@redhat.com> writes:
>
...
>> -static void user_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
>> +static int user_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
>>                                     const QDict *params)
>>  {
>>      int ret;
>> @@ -954,6 +954,8 @@ static void user_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
>>          monitor_resume(mon);
>>          g_free(cb_data);
>>      }
>> +
>> +    return ret;
>>  }
>>  
>
> user_async_cmd_handler() is unreachable since commit 3b5704b.  I got
> code cleaning that up in my tree.  Don't worry about it.

Ok or if you prefer, I can skip this part and other similar cases below.
...
>>  
>>  fail:
>> +    *failed = 1;
>>      g_free(key);
>> -    return NULL;
>> +    return cmd;
>>  }
>>  
>
> From the function's contract:
>
>  * If @cmdline is blank, return NULL.
>  * If it can't be parsed, report to @mon, and return NULL.
>  * Else, insert command arguments into @qdict, and return the command.
>
> Your patch splits the "it can't be parsed" case into "command not found"
> and "arguments can't be parsed", but neglects to update the contract.
> Needs fixing.  Perhaps like this:
>
>  * If @cmdline is blank, return NULL.
>  * If @cmdline doesn't start with a valid command name, report to @mon,
>  * and return NULL.
>  * Else, if the command's arguments can't be parsed, report to @mon,
>  * store 1 through @failed, and return the command.
>  * Else, insert command arguments into @qdict, and return the command.


> The contract wasn't exactly pretty before, and I'm afraid it's
> positively ugly now.
>
> The common cause for such ugliness is doing too much in one function.
> I'd try splitting into a command part and an argument part, so that
>
>     cmd = monitor_parse_command(mon, cmdline, start, table, qdict);
>     if (!cmd) {
>         // bail out
>     }
>
> becomes something like
>
>     cmd = monitor_parse_command(mon, cmdline, start, table, &args);
>     if (!cmd) {
>         // bail out
>     }
>     qdict = monitor_parse_arguments(mon, cmd, args)
>     if (!qdict) {
>         // bail out
>     }
>
> While I encourage you to do this, I won't reject your patch just because
> you don't.

Ok understood, makes sense. Will fix this in next version.

>>  void monitor_set_error(Monitor *mon, QError *qerror)
>> @@ -4114,20 +4118,22 @@ static void handle_user_command(Monitor *mon, const char *cmdline)
>>  {
>>      QDict *qdict;
>>      const mon_cmd_t *cmd;
>> +    int failed = 0;
>>  
>>      qdict = qdict_new();
>>  
>> -    cmd = monitor_parse_command(mon, cmdline, 0, mon->cmd_table, qdict);
>> -    if (!cmd)
>> +    cmd = monitor_parse_command(mon, cmdline, 0, mon->cmd_table,
>> +                                qdict, &failed);
>> +    if (!cmd || failed) {
>>          goto out;
>> +    }
>
> cmd implies !failed, therefore !cmd || failed == !cmd here.  Why not
> simply stick to if (!cmd)?

Note that I changed the old behavior so that now monitor_parse_command()
returns cmd when failed is set. This is so that we have cmd->name. "if (!cmd)"
will be false in that case.

>>  
>>      if (handler_is_async(cmd)) {
>> -        user_async_cmd_handler(mon, cmd, qdict);
>> +        failed = user_async_cmd_handler(mon, cmd, qdict);
>
> As discussed above: unreachable, but don't worry about it.
>
>>      } else if (handler_is_qobject(cmd)) {
>
> This is the "new" HMP command interface.  It's used only with drive_del,
> device_add, client_migrate_info, pcie_aer_inject_error.  The cleanup
> work I mentioned above will get rid of it.  Again, don't worry.

Ok.

>>          QObject *data = NULL;
>>  
>> -        /* XXX: ignores the error code */
>> -        cmd->mhandler.cmd_new(mon, qdict, &data);
>> +        failed = cmd->mhandler.cmd_new(mon, qdict, &data);
>>          assert(!monitor_has_error(mon));
>>          if (data) {
>>              cmd->user_print(mon, data);
>                qobject_decref(data);
>            }
>        } else {
>
> This is the traditional HMP command interface.  Almost all commands use
> it, and after my pending cleanup, it'll be the *only* HMP command
> interface.
>
> It lacks means to communicate command failure.
>
>            cmd->mhandler.cmd(mon, qdict);
>        }
>
> Since you can't set failed in the common case, I recommend not to bother
> setting it in the unreachable and the uncommon case, either.
>
>> @@ -4138,6 +4144,10 @@ static void handle_user_command(Monitor *mon, const char *cmdline)
>>      }
>>  
>>  out:
>> +    if (failed && cmd) {
>
> Recommend (cmd && failed).

Since this path is common whether the command failed or not, I
think it's better to check for "failed" as the first condition.
So, the check on second argument need not be done if the function
succeeds. Actually, taking a second look, I think just
"if (failed) {" should be enough since cmd is guaranteed to be !NULL
when failed is set.

Bandan

>> +        monitor_printf(mon, "Try \"help %s\" for more information\n",
>> +                       cmd->name);
>> +    }
>>      QDECREF(qdict);
>>  }
>
> Cases:
>
> 1. @cmdline is blank
>
>    cmd == NULL && !failed
>
>    We don't print command help.  Good.
>
> 2. @cmdline isn't blank, command not found
>
>    cmd == NULL && !failed
>
>    We don't print command help.  We already printed the error.  Good.
>
> 3. command found, arguments can't be parsed
>
>    cmd != NULL && failed
>
>    We print command help.  We printed the parse error already.  Good.
>
> 4. command found, arguments parsed, command failed
>
>    cmd != NULL, but failed can be anything
>
>    We may or may not print command help.  The command should've printed
>    an error already.  Best we can do as long as the traditional HMP
>    command handler doesn't return status.
>
> 5. command found, arguments parsed, command succeeded
>
>    We don't print command help.  Good.
>
> Works.

  reply	other threads:[~2015-05-15  4:37 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-05-12 21:37 [Qemu-devel] [PATCH] monitor: print help for command errors Bandan Das
2015-05-13  7:10 ` Markus Armbruster
2015-05-13 20:49   ` Bandan Das
2015-05-13 21:08     ` [Qemu-devel] [PATCH] monitor: suggest running "help" " Bandan Das
2015-05-14 11:27       ` Markus Armbruster
2015-05-15  4:37         ` Bandan Das [this message]
2015-05-15 11:29           ` Markus Armbruster

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=jpglhgqh2wt.fsf@redhat.com \
    --to=bsd@redhat.com \
    --cc=armbru@redhat.com \
    --cc=lcapitulino@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).