@@ -18,6 +18,14 @@
#include "qapi/qmp/qdict.h"
#include "qapi/error.h"
+typedef void (QmpDispatchReturn) (QObject *rsp, void *opaque);
+
+typedef struct QmpReturn {
+ QDict *rsp;
+ QmpDispatchReturn *return_cb;
+ void *opaque;
+} QmpReturn;
+
typedef void (QmpCommandFunc)(QDict *, QObject **, Error **);
typedef enum QmpCommandType
@@ -44,7 +52,8 @@ typedef struct QmpCommand
void qmp_register_command(const char *name, QmpCommandFunc *fn,
QmpCommandOptions options);
QmpCommand *qmp_find_command(const char *name);
-QObject *qmp_dispatch(QObject *request, QDict *rsp);
+void qmp_dispatch(QObject *request, QDict *rsp,
+ QmpDispatchReturn *return_cb, void *opaque);
void qmp_disable_command(const char *name);
void qmp_enable_command(const char *name);
bool qmp_command_is_enabled(const QmpCommand *cmd);
@@ -53,6 +62,7 @@ bool qmp_has_success_response(const QmpCommand *cmd);
QObject *qmp_build_error_object(Error *err);
typedef void (*qmp_cmd_callback_fn)(QmpCommand *cmd, void *opaque);
void qmp_for_each_command(qmp_cmd_callback_fn fn, void *opaque);
+void qmp_return(QmpReturn *qret, QObject *cmd_rsp);
+void qmp_return_error(QmpReturn *qret, Error *err);
#endif
-
@@ -3570,6 +3570,13 @@ static QDict *qmp_check_input_obj(QObject *input_obj, Error **errp)
return input_dict;
}
+static void qmp_dispatch_return(QObject *rsp, void *opaque)
+{
+ Monitor *mon = opaque;
+
+ monitor_json_emitter(mon, rsp);
+}
+
static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
{
QObject *req, *rsp, *id = NULL;
@@ -3606,15 +3613,13 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
goto err_out;
}
- rsp = qmp_dispatch(req, rqdict);
+ qmp_dispatch(req, rqdict, qmp_dispatch_return, mon);
+ rsp = NULL;
err_out:
if (err) {
qdict_put_obj(rqdict, "error", qmp_build_error_object(err));
error_free(err);
- }
-
- if (rsp) {
monitor_json_emitter(mon, rsp);
}
@@ -60,7 +60,7 @@ static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
return dict;
}
-static QObject *do_qmp_dispatch(QObject *request, Error **errp)
+static QObject *do_qmp_dispatch(QObject *request, QmpReturn *qret, Error **errp)
{
Error *local_err = NULL;
const char *command;
@@ -118,23 +118,50 @@ QObject *qmp_build_error_object(Error *err)
error_get_pretty(err));
}
-QObject *qmp_dispatch(QObject *request, QDict *rsp)
+static void do_qmp_return(QmpReturn *qret)
+{
+ QDict *rsp = qret->rsp;
+
+ qret->return_cb(QOBJECT(rsp), qret->opaque);
+
+ qobject_decref(QOBJECT(rsp));
+ g_free(qret);
+}
+
+void qmp_return(QmpReturn *qret, QObject *cmd_rsp)
+{
+ qdict_put_obj(qret->rsp, "return", cmd_rsp);
+
+ do_qmp_return(qret);
+}
+
+void qmp_return_error(QmpReturn *qret, Error *err)
+{
+ qdict_put_obj(qret->rsp, "error", qmp_build_error_object(err));
+ error_free(err);
+
+ do_qmp_return(qret);
+}
+
+void qmp_dispatch(QObject *request, QDict *rsp,
+ QmpDispatchReturn *return_cb, void *opaque)
{
Error *err = NULL;
+ QmpReturn *qret = g_new0(QmpReturn, 1);
QObject *ret;
- ret = do_qmp_dispatch(request, &err);
+ assert(return_cb);
+
+ qret->rsp = rsp ?: qdict_new();
+ qret->return_cb = return_cb;
+ qret->opaque = opaque;
+
+ ret = do_qmp_dispatch(request, qret, &err);
- rsp = rsp ?: qdict_new();
if (err) {
- qdict_put_obj(rsp, "error", qmp_build_error_object(err));
- error_free(err);
+ assert(!ret);
+ qmp_return_error(qret, err);
} else if (ret) {
- qdict_put_obj(rsp, "return", ret);
- } else {
- QDECREF(rsp);
- return NULL;
+ qmp_return(qret, ret);
}
-
- return QOBJECT(rsp);
}
@@ -546,21 +546,21 @@ static int send_response(GAState *s, QObject *payload)
return 0;
}
-static void process_command(GAState *s, QDict *req)
+static void dispatch_return_cb(QObject *rsp, void *opaque)
{
- QObject *rsp = NULL;
- int ret;
+ GAState *s = opaque;
+ int ret = send_response(s, rsp);
+
+ if (ret) {
+ g_warning("error sending response: %s", strerror(ret));
+ }
+}
+static void process_command(GAState *s, QDict *req)
+{
g_assert(req);
g_debug("processing command");
- rsp = qmp_dispatch(QOBJECT(req), NULL);
- if (rsp) {
- ret = send_response(s, rsp);
- if (ret) {
- g_warning("error sending response: %s", strerror(ret));
- }
- qobject_decref(rsp);
- }
+ qmp_dispatch(QOBJECT(req), NULL, dispatch_return_cb, s);
}
/* handle requests/control events coming in over the channel */
@@ -76,53 +76,57 @@ __org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a,
return ret;
}
+static void dispatch_cmd_return(QObject *resp, void *opaque)
+{
+ assert(resp != NULL);
+ assert(!qdict_haskey(qobject_to_qdict(resp), "error"));
+}
/* test commands with no input and no return value */
static void test_dispatch_cmd(void)
{
QDict *req = qdict_new();
- QObject *resp;
qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd")));
- resp = qmp_dispatch(QOBJECT(req), NULL);
- assert(resp != NULL);
- assert(!qdict_haskey(qobject_to_qdict(resp), "error"));
+ qmp_dispatch(QOBJECT(req), NULL, dispatch_cmd_return, NULL);
- qobject_decref(resp);
QDECREF(req);
}
+static void dispatch_cmd_error_return(QObject *resp, void *opaque)
+{
+ assert(resp != NULL);
+ assert(qdict_haskey(qobject_to_qdict(resp), "error"));
+}
+
/* test commands that return an error due to invalid parameters */
static void test_dispatch_cmd_error(void)
{
QDict *req = qdict_new();
- QObject *resp;
qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2")));
- resp = qmp_dispatch(QOBJECT(req), NULL);
- assert(resp != NULL);
- assert(qdict_haskey(qobject_to_qdict(resp), "error"));
+ qmp_dispatch(QOBJECT(req), NULL, dispatch_cmd_error_return, NULL);
- qobject_decref(resp);
QDECREF(req);
}
-static QObject *test_qmp_dispatch(QDict *req)
-{
- QObject *resp_obj;
- QDict *resp;
- QObject *ret;
+static QObject *ret;
- resp_obj = qmp_dispatch(QOBJECT(req), NULL);
- assert(resp_obj);
- resp = qobject_to_qdict(resp_obj);
+static void qmp_dispatch_return(QObject *resp_obj, void *opaque)
+{
+ QDict *resp = qobject_to_qdict(resp_obj);
assert(resp && !qdict_haskey(resp, "error"));
ret = qdict_get(resp, "return");
assert(ret);
qobject_incref(ret);
- qobject_decref(resp_obj);
+}
+
+static QObject *test_qmp_dispatch(QDict *req)
+{
+ qmp_dispatch(QOBJECT(req), NULL, qmp_dispatch_return, NULL);
+
return ret;
}