From acceb4d99fcdabded6ba432402365adb63205196 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Fri, 2 Sep 2011 12:34:44 -0500 Subject: [PATCH 01/26] error: let error_is_type take a NULL error Reported-by: Luiz Capitulino Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- error.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/error.c b/error.c index b80275261..68c0039db 100644 --- a/error.c +++ b/error.c @@ -97,6 +97,10 @@ bool error_is_type(Error *err, const char *fmt) char *ptr; char *end; + if (!err) { + return false; + } + ptr = strstr(fmt, "'class': '"); assert(ptr != NULL); ptr += strlen("'class': '"); From 2a82d936a2bda9cb01d05fc91845e82001b78632 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Fri, 2 Sep 2011 12:34:45 -0500 Subject: [PATCH 02/26] qerror: add qerror_report_err() This provides a bridge between Error (new error mechanism) and QError (old error mechanism). Errors can be propagated whereas QError cannot. The minor evilness avoids layering violations. Since QError should go away RSN, it seems like a reasonable hack. Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- qerror.c | 33 +++++++++++++++++++++++++++++++++ qerror.h | 2 ++ 2 files changed, 35 insertions(+) diff --git a/qerror.c b/qerror.c index c591a5443..68998d4ba 100644 --- a/qerror.c +++ b/qerror.c @@ -482,6 +482,39 @@ void qerror_report_internal(const char *file, int linenr, const char *func, } } +/* Evil... */ +struct Error +{ + QDict *obj; + const char *fmt; + char *msg; +}; + +void qerror_report_err(Error *err) +{ + QError *qerr; + int i; + + qerr = qerror_new(); + loc_save(&qerr->loc); + QINCREF(err->obj); + qerr->error = err->obj; + + for (i = 0; qerror_table[i].error_fmt; i++) { + if (strcmp(qerror_table[i].error_fmt, err->fmt) == 0) { + qerr->entry = &qerror_table[i]; + break; + } + } + + if (monitor_cur_is_qmp()) { + monitor_set_error(cur_mon, qerr); + } else { + qerror_print(qerr); + QDECREF(qerr); + } +} + /** * qobject_to_qerror(): Convert a QObject into a QError */ diff --git a/qerror.h b/qerror.h index d4070015f..d4bfcfd16 100644 --- a/qerror.h +++ b/qerror.h @@ -15,6 +15,7 @@ #include "qdict.h" #include "qstring.h" #include "qemu-error.h" +#include "error.h" #include typedef struct QErrorStringTable { @@ -39,6 +40,7 @@ QString *qerror_human(const QError *qerror); void qerror_print(QError *qerror); void qerror_report_internal(const char *file, int linenr, const char *func, const char *fmt, ...) GCC_FMT_ATTR(4, 5); +void qerror_report_err(Error *err); QString *qerror_format(const char *fmt, QDict *error); #define qerror_report(fmt, ...) \ qerror_report_internal(__FILE__, __LINE__, __func__, fmt, ## __VA_ARGS__) From 776574d6417cf623fb071987cdd2c6bc13271dc2 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Fri, 2 Sep 2011 12:34:46 -0500 Subject: [PATCH 03/26] qapi: add code generation support for middle mode To get the ball rolling merging QAPI, this patch introduces a "middle mode" to the code generator. In middle mode, the code generator generates marshalling functions that are compatible with the current QMP server. We absolutely need to replace the current QMP server in order to support proper asynchronous commands but using a middle mode provides a middle-ground that lets us start converting commands in tree. Note that all of the commands have been converted already in my glib branch. Middle mode only exists until we finish merging them from my branch into the main tree. Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- qapi/qapi-types-core.h | 3 ++ scripts/qapi-commands.py | 81 ++++++++++++++++++++++++++++++++-------- scripts/qapi-types.py | 3 ++ scripts/qapi.py | 4 +- 4 files changed, 75 insertions(+), 16 deletions(-) diff --git a/qapi/qapi-types-core.h b/qapi/qapi-types-core.h index a79bc2b3c..27e6be0a8 100644 --- a/qapi/qapi-types-core.h +++ b/qapi/qapi-types-core.h @@ -17,4 +17,7 @@ #include "qemu-common.h" #include "error.h" +/* FIXME this is temporary until we remove middle mode */ +#include "monitor.h" + #endif diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index bf617401a..27768049a 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -167,9 +167,10 @@ qmp_input_visitor_cleanup(mi); pop_indent() return ret.rstrip() -def gen_marshal_output(name, args, ret_type): +def gen_marshal_output(name, args, ret_type, middle_mode): if not ret_type: return "" + ret = mcgen(''' static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_out, Error **errp) { @@ -188,16 +189,34 @@ static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_o qapi_dealloc_visitor_cleanup(md); } ''', - c_ret_type=c_type(ret_type), c_name=c_var(name), ret_type=ret_type) + c_ret_type=c_type(ret_type), c_name=c_var(name), + ret_type=ret_type) return ret -def gen_marshal_input(name, args, ret_type): +def gen_marshal_input_decl(name, args, ret_type, middle_mode): + if middle_mode: + return 'int qmp_marshal_input_%s(Monitor *mon, const QDict *qdict, QObject **ret)' % c_var(name) + else: + return 'static void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_var(name) + + + +def gen_marshal_input(name, args, ret_type, middle_mode): + hdr = gen_marshal_input_decl(name, args, ret_type, middle_mode) + ret = mcgen(''' -static void qmp_marshal_input_%(c_name)s(QDict *args, QObject **ret, Error **errp) +%(header)s { ''', - c_name=c_var(name)) + header=hdr) + + if middle_mode: + ret += mcgen(''' + Error *local_err = NULL; + Error **errp = &local_err; + QDict *args = (QDict *)qdict; +''') if ret_type: if c_type(ret_type).endswith("*"): @@ -220,6 +239,10 @@ static void qmp_marshal_input_%(c_name)s(QDict *args, QObject **ret, Error **err visitor_input_containers_decl=gen_visitor_input_containers_decl(args), visitor_input_vars_decl=gen_visitor_input_vars_decl(args), visitor_input_block=gen_visitor_input_block(args, "QOBJECT(args)")) + else: + ret += mcgen(''' + (void)args; +''') ret += mcgen(''' if (error_is_set(errp)) { @@ -234,10 +257,29 @@ out: ''') ret += mcgen(''' %(visitor_input_block_cleanup)s - return; -} ''', - visitor_input_block_cleanup=gen_visitor_input_block(args, None, dealloc=True)) + visitor_input_block_cleanup=gen_visitor_input_block(args, None, + dealloc=True)) + + if middle_mode: + ret += mcgen(''' + + if (local_err) { + qerror_report_err(local_err); + error_free(local_err); + return -1; + } + return 0; +''') + else: + ret += mcgen(''' + return; +''') + + ret += mcgen(''' +} +''') + return ret def gen_registry(commands): @@ -284,7 +326,7 @@ def gen_command_decl_prologue(header, guard, prefix=""): #include "error.h" ''', - header=basename(h_file), guard=guardname(h_file), prefix=prefix) + header=basename(header), guard=guardname(header), prefix=prefix) return ret def gen_command_def_prologue(prefix="", proxy=False): @@ -317,11 +359,11 @@ def gen_command_def_prologue(prefix="", proxy=False): prefix=prefix) if not proxy: ret += '#include "%sqmp-commands.h"' % prefix - return ret + "\n" + return ret + "\n\n" try: - opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:", ["prefix=", "output-dir=", "type="]) + opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:m", ["prefix=", "output-dir=", "type=", "middle"]) except getopt.GetoptError, err: print str(err) sys.exit(1) @@ -331,6 +373,7 @@ prefix = "" dispatch_type = "sync" c_file = 'qmp-marshal.c' h_file = 'qmp-commands.h' +middle_mode = False for o, a in opts: if o in ("-p", "--prefix"): @@ -339,6 +382,8 @@ for o, a in opts: output_dir = a + "/" elif o in ("-t", "--type"): dispatch_type = a + elif o in ("-m", "--middle"): + middle_mode = True c_file = output_dir + prefix + c_file h_file = output_dir + prefix + h_file @@ -370,14 +415,20 @@ if dispatch_type == "sync": ret = generate_command_decl(cmd['command'], arglist, ret_type) + "\n" fdecl.write(ret) if ret_type: - ret = gen_marshal_output(cmd['command'], arglist, ret_type) + "\n" + ret = gen_marshal_output(cmd['command'], arglist, ret_type, middle_mode) + "\n" fdef.write(ret) - ret = gen_marshal_input(cmd['command'], arglist, ret_type) + "\n" + + if middle_mode: + fdecl.write('%s;\n' % gen_marshal_input_decl(cmd['command'], arglist, ret_type, middle_mode)) + + ret = gen_marshal_input(cmd['command'], arglist, ret_type, middle_mode) + "\n" fdef.write(ret) fdecl.write("\n#endif\n"); - ret = gen_registry(commands) - fdef.write(ret) + + if not middle_mode: + ret = gen_registry(commands) + fdef.write(ret) fdef.flush() fdef.close() diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index cece32546..fc0f7af8f 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -268,3 +268,6 @@ fdecl.write(''' fdecl.flush() fdecl.close() + +fdef.flush() +fdef.close() diff --git a/scripts/qapi.py b/scripts/qapi.py index 56af2329b..52999763e 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -200,4 +200,6 @@ def basename(filename): return filename.split("/")[-1] def guardname(filename): - return filename.replace("/", "_").replace("-", "_").split(".")[0].upper() + if filename.startswith('./'): + filename = filename[2:] + return filename.replace("/", "_").replace("-", "_").split(".")[0].upper() + '_H' From e3193601c84558c303b1773379da76fce80c0a56 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Fri, 2 Sep 2011 12:34:47 -0500 Subject: [PATCH 04/26] qapi: use middle mode in QMP server Use the new middle mode within the existing QMP server. Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- Makefile | 12 ++++++++++++ Makefile.objs | 2 ++ Makefile.target | 6 +++--- monitor.c | 9 ++++----- qapi-schema.json | 3 +++ 5 files changed, 24 insertions(+), 8 deletions(-) create mode 100644 qapi-schema.json diff --git a/Makefile b/Makefile index 6ed3194fd..55ee79c77 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,7 @@ GENERATED_HEADERS = config-host.h trace.h qemu-options.def ifeq ($(TRACE_BACKEND),dtrace) GENERATED_HEADERS += trace-dtrace.h endif +GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h ifneq ($(wildcard config-host.mak),) # Put the all: rule here so that config-host.mak can contain dependencies. @@ -187,9 +188,20 @@ $(qapi-dir)/qga-qapi-types.h: $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scr $(qapi-dir)/qga-qapi-visit.c: $(qapi-dir)/qga-qapi-visit.h $(qapi-dir)/qga-qapi-visit.h: $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-visit.py $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py -o "$(qapi-dir)" -p "qga-" < $<, " GEN $@") +$(qapi-dir)/qga-qmp-commands.h: $(qapi-dir)/qga-qmp-marshal.c $(qapi-dir)/qga-qmp-marshal.c: $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-commands.py $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py -o "$(qapi-dir)" -p "qga-" < $<, " GEN $@") +qapi-types.c: qapi-types.h +qapi-types.h: $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py -o "." < $<, " GEN $@") +qapi-visit.c: qapi-visit.h +qapi-visit.h: $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py -o "." < $<, " GEN $@") +qmp-commands.h: qmp-marshal.c +qmp-marshal.c: $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py -m -o "." < $<, " GEN $@") + test-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y) test-visitor: test-visitor.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o $(qapi-obj-y) error.o osdep.o $(oslib-obj-y) qjson.o json-streamer.o json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o diff --git a/Makefile.objs b/Makefile.objs index 8d23fbbbe..587ec3686 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -406,6 +406,8 @@ qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o qmp-output-visitor.o qapi- qapi-nested-y += qmp-registry.o qmp-dispatch.o qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y)) +common-obj-y += qmp-marshal.o qapi-visit.o qapi-types.o $(qapi-obj-y) + ###################################################################### # guest agent diff --git a/Makefile.target b/Makefile.target index 88d2f1fb7..b5ed5dffe 100644 --- a/Makefile.target +++ b/Makefile.target @@ -375,7 +375,7 @@ obj-xtensa-y += xtensa-semi.o main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) -monitor.o: hmp-commands.h qmp-commands.h +monitor.o: hmp-commands.h qmp-commands-old.h $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS) @@ -407,13 +407,13 @@ gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/scripts/feature_to_c.sh hmp-commands.h: $(SRC_PATH)/hmp-commands.hx $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@") -qmp-commands.h: $(SRC_PATH)/qmp-commands.hx +qmp-commands-old.h: $(SRC_PATH)/qmp-commands.hx $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@") clean: rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o rm -f *.d */*.d tcg/*.o ide/*.o 9pfs/*.o - rm -f hmp-commands.h qmp-commands.h gdbstub-xml.c + rm -f hmp-commands.h qmp-commands-old.h gdbstub-xml.c ifdef CONFIG_TRACE_SYSTEMTAP rm -f *.stp endif diff --git a/monitor.c b/monitor.c index d323ea585..e267d5899 100644 --- a/monitor.c +++ b/monitor.c @@ -122,6 +122,7 @@ typedef struct mon_cmd_t { int (*cmd_async)(Monitor *mon, const QDict *params, MonitorCompletion *cb, void *opaque); } mhandler; + bool qapi; int flags; } mon_cmd_t; @@ -3182,7 +3183,7 @@ static const mon_cmd_t info_cmds[] = { }; static const mon_cmd_t qmp_cmds[] = { -#include "qmp-commands.h" +#include "qmp-commands-old.h" { /* NULL */ }, }; @@ -5107,12 +5108,10 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) goto err_out; } - if (strstart(cmd_name, "query-", &query_cmd)) { + cmd = qmp_find_cmd(cmd_name); + if (!cmd && strstart(cmd_name, "query-", &query_cmd)) { cmd = qmp_find_query_cmd(query_cmd); - } else { - cmd = qmp_find_cmd(cmd_name); } - if (!cmd) { qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name); goto err_out; diff --git a/qapi-schema.json b/qapi-schema.json new file mode 100644 index 000000000..7fcefdb73 --- /dev/null +++ b/qapi-schema.json @@ -0,0 +1,3 @@ +# -*- Mode: Python -*- +# +# QAPI Schema From 15e43e64b6bac61811e829634ee048e8de4c976d Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Wed, 14 Sep 2011 14:30:00 -0500 Subject: [PATCH 05/26] qapi: fixup command generation for functions that return list types Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- scripts/qapi-commands.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index 27768049a..c947ba420 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -17,12 +17,18 @@ import os import getopt import errno +def type_visitor(name): + if type(name) == list: + return 'visit_type_%sList' % name[0] + else: + return 'visit_type_%s' % name + def generate_decl_enum(name, members, genlist=True): return mcgen(''' -void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp); +void %(visitor)s(Visitor *m, %(name)s * obj, const char *name, Error **errp); ''', - name=name) + visitor=type_visitor(name)) def generate_command_decl(name, args, ret_type): arglist="" @@ -146,9 +152,10 @@ if (has_%(c_name)s) { c_name=c_var(argname), name=argname) push_indent() ret += mcgen(''' -visit_type_%(argtype)s(v, &%(c_name)s, "%(name)s", errp); +%(visitor)s(v, &%(c_name)s, "%(name)s", errp); ''', - c_name=c_var(argname), name=argname, argtype=argtype) + c_name=c_var(argname), name=argname, argtype=argtype, + visitor=type_visitor(argtype)) if optional: pop_indent() ret += mcgen(''' @@ -179,18 +186,18 @@ static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_o Visitor *v; v = qmp_output_get_visitor(mo); - visit_type_%(ret_type)s(v, &ret_in, "unused", errp); + %(visitor)s(v, &ret_in, "unused", errp); if (!error_is_set(errp)) { *ret_out = qmp_output_get_qobject(mo); } qmp_output_visitor_cleanup(mo); v = qapi_dealloc_get_visitor(md); - visit_type_%(ret_type)s(v, &ret_in, "unused", errp); + %(visitor)s(v, &ret_in, "unused", errp); qapi_dealloc_visitor_cleanup(md); } ''', - c_ret_type=c_type(ret_type), c_name=c_var(name), - ret_type=ret_type) + c_ret_type=c_type(ret_type), c_name=c_var(name), + visitor=type_visitor(ret_type)) return ret From 5666dd19dd95d966be00d0c3e7efdfaecc096ff3 Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Thu, 15 Sep 2011 14:39:52 -0500 Subject: [PATCH 06/26] qapi: dealloc visitor, fix premature free and iteration logic Currently we do 3 things wrong: 1) The list iterator, in practice, is used in a manner where the pointer we pass in is the same as the pointer we assign the output to from visit_next_list(). This causes an infinite loop where we keep freeing the same structures. 2) We attempt to free list->value rather than list. visit_type_ handles this. We should only be concerned with the containing list. 3) We free prematurely: iterator function will continue accessing values we've already freed. This patch should fix all of these issues. QmpOutputVisitor also suffers from 1). Reviewed-by: Anthony Liguori Signed-off-by: Michael Roth Signed-off-by: Luiz Capitulino --- qapi/qapi-dealloc-visitor.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c index f6290611f..6b586ade1 100644 --- a/qapi/qapi-dealloc-visitor.c +++ b/qapi/qapi-dealloc-visitor.c @@ -26,6 +26,7 @@ struct QapiDeallocVisitor { Visitor visitor; QTAILQ_HEAD(, StackEntry) stack; + bool is_list_head; }; static QapiDeallocVisitor *to_qov(Visitor *v) @@ -70,15 +71,24 @@ static void qapi_dealloc_end_struct(Visitor *v, Error **errp) static void qapi_dealloc_start_list(Visitor *v, const char *name, Error **errp) { + QapiDeallocVisitor *qov = to_qov(v); + qov->is_list_head = true; } -static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList **list, +static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList **listp, Error **errp) { - GenericList *retval = *list; - g_free(retval->value); - *list = retval->next; - return retval; + GenericList *list = *listp; + QapiDeallocVisitor *qov = to_qov(v); + + if (!qov->is_list_head) { + *listp = list->next; + g_free(list); + return *listp; + } + + qov->is_list_head = false; + return list; } static void qapi_dealloc_end_list(Visitor *v, Error **errp) From 75b96aca6ff53c7e782efe670045376df4f7d199 Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Thu, 15 Sep 2011 14:39:53 -0500 Subject: [PATCH 07/26] qapi: generate qapi_free_* functions for *List types Reviewed-by: Anthony Liguori Signed-off-by: Michael Roth Signed-off-by: Luiz Capitulino --- scripts/qapi-types.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index fc0f7af8f..4797a7081 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -254,6 +254,8 @@ for expr in exprs: ret = "\n" if expr.has_key('type'): ret += generate_struct(expr['type'], "", expr['data']) + "\n" + ret += generate_type_cleanup_decl(expr['type'] + "List") + fdef.write(generate_type_cleanup(expr['type'] + "List") + "\n") ret += generate_type_cleanup_decl(expr['type']) fdef.write(generate_type_cleanup(expr['type']) + "\n") elif expr.has_key('union'): From 5cd5f0d059ecb9ce8cc214b5e7b8b6d473b50964 Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Thu, 15 Sep 2011 14:39:54 -0500 Subject: [PATCH 08/26] qapi: add test cases for generated free functions Signed-off-by: Michael Roth Signed-off-by: Luiz Capitulino --- test-qmp-commands.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test-qmp-commands.c b/test-qmp-commands.c index f142cc616..fa5a7bd8d 100644 --- a/test-qmp-commands.c +++ b/test-qmp-commands.c @@ -98,6 +98,34 @@ static void test_dispatch_cmd_io(void) QDECREF(req); } +/* test generated dealloc functions for generated types */ +static void test_dealloc_types(void) +{ + UserDefOne *ud1test, *ud1a, *ud1b; + UserDefOneList *ud1list; + + ud1test = g_malloc0(sizeof(UserDefOne)); + ud1test->integer = 42; + ud1test->string = g_strdup("hi there 42"); + + qapi_free_UserDefOne(ud1test); + + ud1a = g_malloc0(sizeof(UserDefOne)); + ud1a->integer = 43; + ud1a->string = g_strdup("hi there 43"); + + ud1b = g_malloc0(sizeof(UserDefOne)); + ud1b->integer = 44; + ud1b->string = g_strdup("hi there 44"); + + ud1list = g_malloc0(sizeof(UserDefOneList)); + ud1list->value = ud1a; + ud1list->next = g_malloc0(sizeof(UserDefOneList)); + ud1list->next->value = ud1b; + + qapi_free_UserDefOneList(ud1list); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -105,6 +133,7 @@ int main(int argc, char **argv) g_test_add_func("/0.15/dispatch_cmd", test_dispatch_cmd); g_test_add_func("/0.15/dispatch_cmd_error", test_dispatch_cmd_error); g_test_add_func("/0.15/dispatch_cmd_io", test_dispatch_cmd_io); + g_test_add_func("/0.15/dealloc_types", test_dealloc_types); module_call_init(MODULE_INIT_QAPI); g_test_run(); From 0b9d854230737b214c01e89f0b679ea36fd59e5e Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Mon, 19 Sep 2011 19:03:10 -0500 Subject: [PATCH 09/26] qapi: dealloc visitor, support freeing of nested lists Previously our logic for keeping track of when we're visiting the head of a list was done via a global bool. This can be overwritten if dealing with nested lists, so use stack entries to track this instead. Reviewed-by: Anthony Liguori Signed-off-by: Michael Roth Signed-off-by: Luiz Capitulino --- qapi/qapi-dealloc-visitor.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c index 6b586ade1..a15452373 100644 --- a/qapi/qapi-dealloc-visitor.c +++ b/qapi/qapi-dealloc-visitor.c @@ -19,6 +19,7 @@ typedef struct StackEntry { void *value; + bool is_list_head; QTAILQ_ENTRY(StackEntry) node; } StackEntry; @@ -39,6 +40,11 @@ static void qapi_dealloc_push(QapiDeallocVisitor *qov, void *value) StackEntry *e = g_malloc0(sizeof(*e)); e->value = value; + + /* see if we're just pushing a list head tracker */ + if (value == NULL) { + e->is_list_head = true; + } QTAILQ_INSERT_HEAD(&qov->stack, e, node); } @@ -72,7 +78,7 @@ static void qapi_dealloc_end_struct(Visitor *v, Error **errp) static void qapi_dealloc_start_list(Visitor *v, const char *name, Error **errp) { QapiDeallocVisitor *qov = to_qov(v); - qov->is_list_head = true; + qapi_dealloc_push(qov, NULL); } static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList **listp, @@ -80,19 +86,27 @@ static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList **listp, { GenericList *list = *listp; QapiDeallocVisitor *qov = to_qov(v); + StackEntry *e = QTAILQ_FIRST(&qov->stack); - if (!qov->is_list_head) { - *listp = list->next; - g_free(list); - return *listp; + if (e && e->is_list_head) { + e->is_list_head = false; + return list; } - qov->is_list_head = false; - return list; + if (list) { + list = list->next; + g_free(*listp); + return list; + } + + return NULL; } static void qapi_dealloc_end_list(Visitor *v, Error **errp) { + QapiDeallocVisitor *qov = to_qov(v); + void *obj = qapi_dealloc_pop(qov); + assert(obj == NULL); /* should've been list head tracker with no payload */ } static void qapi_dealloc_type_str(Visitor *v, char **obj, const char *name, From e1bc2f7b3fb19ab2abcec3d5b15e045b00ae9da1 Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Mon, 19 Sep 2011 19:03:11 -0500 Subject: [PATCH 10/26] qapi: modify visitor code generation for list iteration Modify logic such that we never assign values to the list head argument to progress through the list on subsequent iterations, instead rely only on having our return value passed back in as an argument on the next call. Also update QMP I/O visitors and test cases accordingly, and add a missing test case for QmpOutputVisitor. Reviewed-by: Anthony Liguori Signed-off-by: Michael Roth Signed-off-by: Luiz Capitulino --- qapi/qmp-input-visitor.c | 4 ++-- qapi/qmp-output-visitor.c | 20 ++++++++++++---- scripts/qapi-visit.py | 4 ++-- test-visitor.c | 50 ++++++++++++++++++++++++++++++++------- 4 files changed, 61 insertions(+), 17 deletions(-) diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c index fcf8bf920..8cbc0abcf 100644 --- a/qapi/qmp-input-visitor.c +++ b/qapi/qmp-input-visitor.c @@ -144,8 +144,6 @@ static GenericList *qmp_input_next_list(Visitor *v, GenericList **list, } (*list)->next = entry; } - *list = entry; - return entry; } @@ -240,9 +238,11 @@ static void qmp_input_type_enum(Visitor *v, int *obj, const char *strings[], if (strings[value] == NULL) { error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null"); + g_free(enum_str); return; } + g_free(enum_str); *obj = value; } diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c index 4419a3164..d67724ea4 100644 --- a/qapi/qmp-output-visitor.c +++ b/qapi/qmp-output-visitor.c @@ -20,6 +20,7 @@ typedef struct QStackEntry { QObject *value; + bool is_list_head; QTAILQ_ENTRY(QStackEntry) node; } QStackEntry; @@ -45,6 +46,9 @@ static void qmp_output_push_obj(QmpOutputVisitor *qov, QObject *value) QStackEntry *e = g_malloc0(sizeof(*e)); e->value = value; + if (qobject_type(e->value) == QTYPE_QLIST) { + e->is_list_head = true; + } QTAILQ_INSERT_HEAD(&qov->stack, e, node); } @@ -122,12 +126,20 @@ static void qmp_output_start_list(Visitor *v, const char *name, Error **errp) qmp_output_push(qov, list); } -static GenericList *qmp_output_next_list(Visitor *v, GenericList **list, +static GenericList *qmp_output_next_list(Visitor *v, GenericList **listp, Error **errp) { - GenericList *retval = *list; - *list = retval->next; - return retval; + GenericList *list = *listp; + QmpOutputVisitor *qov = to_qov(v); + QStackEntry *e = QTAILQ_FIRST(&qov->stack); + + assert(e); + if (e->is_list_head) { + e->is_list_head = false; + return list; + } + + return list ? list->next : NULL; } static void qmp_output_end_list(Visitor *v, Error **errp) diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index 252230ef2..62de83d0f 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -79,11 +79,11 @@ def generate_visit_list(name, members): void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp) { - GenericList *i; + GenericList *i, **head = (GenericList **)obj; visit_start_list(m, name, errp); - for (i = visit_next_list(m, (GenericList **)obj, errp); i; i = visit_next_list(m, &i, errp)) { + for (*head = i = visit_next_list(m, head, errp); i; i = visit_next_list(m, &i, errp)) { %(name)sList *native_i = (%(name)sList *)i; visit_type_%(name)s(m, &native_i->value, NULL, errp); } diff --git a/test-visitor.c b/test-visitor.c index b7717deb6..847ce14ea 100644 --- a/test-visitor.c +++ b/test-visitor.c @@ -27,11 +27,11 @@ static void visit_type_TestStruct(Visitor *v, TestStruct **obj, const char *name static void visit_type_TestStructList(Visitor *m, TestStructList ** obj, const char *name, Error **errp) { - GenericList *i; + GenericList *i, **head = (GenericList **)obj; visit_start_list(m, name, errp); - for (i = visit_next_list(m, (GenericList **)obj, errp); i; i = visit_next_list(m, &i, errp)) { + for (*head = i = visit_next_list(m, head, errp); i; i = visit_next_list(m, &i, errp)) { TestStructList *native_i = (TestStructList *)i; visit_type_TestStruct(m, &native_i->value, NULL, errp); } @@ -50,6 +50,8 @@ static void test_visitor_core(void) TestStructList *lts = NULL; Error *err = NULL; QObject *obj; + QList *qlist; + QDict *qdict; QString *str; int64_t value = 0; @@ -96,7 +98,9 @@ static void test_visitor_core(void) g_assert(pts->y == 84); qobject_decref(obj); + g_free(pts); + /* test list input visitor */ obj = qobject_from_json("[{'x': 42, 'y': 84}, {'x': 12, 'y': 24}]"); mi = qmp_input_visitor_new(obj); v = qmp_input_get_visitor(mi); @@ -110,14 +114,41 @@ static void test_visitor_core(void) g_assert(lts->value->x == 42); g_assert(lts->value->y == 84); - lts = lts->next; - g_assert(lts != NULL); - g_assert(lts->value->x == 12); - g_assert(lts->value->y == 24); - - g_assert(lts->next == NULL); + g_assert(lts->next != NULL); + g_assert(lts->next->value->x == 12); + g_assert(lts->next->value->y == 24); + g_assert(lts->next->next == NULL); qobject_decref(obj); + + /* test list output visitor */ + mo = qmp_output_visitor_new(); + v = qmp_output_get_visitor(mo); + visit_type_TestStructList(v, <s, NULL, &err); + if (err) { + g_error("%s", error_get_pretty(err)); + } + obj = qmp_output_get_qobject(mo); + g_print("obj: %s\n", qstring_get_str(qobject_to_json(obj))); + + qlist = qobject_to_qlist(obj); + assert(qlist); + obj = qlist_pop(qlist); + qdict = qobject_to_qdict(obj); + assert(qdict); + assert(qdict_get_int(qdict, "x") == 42); + assert(qdict_get_int(qdict, "y") == 84); + qobject_decref(obj); + + obj = qlist_pop(qlist); + qdict = qobject_to_qdict(obj); + assert(qdict); + assert(qdict_get_int(qdict, "x") == 12); + assert(qdict_get_int(qdict, "y") == 24); + qobject_decref(obj); + + qmp_output_visitor_cleanup(mo); + QDECREF(qlist); } /* test deep nesting with refs to other user-defined types */ @@ -286,7 +317,8 @@ static void test_nested_enums(void) g_assert(nested_enums_cpy->has_enum2 == false); g_assert(nested_enums_cpy->has_enum4 == true); - qobject_decref(obj); + qmp_output_visitor_cleanup(mo); + qmp_input_visitor_cleanup(mi); qapi_free_NestedEnumsOne(nested_enums); qapi_free_NestedEnumsOne(nested_enums_cpy); } From d2a80d6bb3fdf319d28f25eb034b32a9f3da7334 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 28 Sep 2011 16:56:56 -0300 Subject: [PATCH 11/26] qapi: Don't use c_var() on enum strings Otherwise if we have something like 'foo-bar' in the schema, it will be generated as 'foo_bar' in the string lookup table. c_var() is good for C variables, but not for enum strings. Signed-off-by: Luiz Capitulino --- scripts/qapi-types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 4797a7081..3bacc0c0d 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -70,7 +70,7 @@ const char *%(name)s_lookup[] = { ret += mcgen(''' "%(value)s", ''', - value=c_var(value).lower()) + value=value.lower()) ret += mcgen(''' NULL, From 303b54b1a2611eda47abb28546869c49b5664f59 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 30 Sep 2011 12:43:27 -0300 Subject: [PATCH 12/26] qapi: Automatically generate a _MAX value for enums It's the last value in the enum and is very useful for the C implementation. Signed-off-by: Luiz Capitulino --- scripts/qapi-types.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 3bacc0c0d..f64d84c39 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -91,8 +91,11 @@ typedef enum %(name)s ''', name=name) + # append automatically generated _MAX value + enum_values = values + [ 'MAX' ] + i = 0 - for value in values: + for value in enum_values: enum_decl += mcgen(''' %(abbrev)s_%(value)s = %(i)d, ''', From 48a32bedfed0ea5b30bdbb470c0520acdadc3bf2 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Fri, 2 Sep 2011 12:34:48 -0500 Subject: [PATCH 13/26] qapi: convert query-name A simple example conversion 'info name'. This also adds the new files for QMP and HMP. Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- Makefile.objs | 1 + hmp.c | 26 ++++++++++++++++++++++++++ hmp.h | 22 ++++++++++++++++++++++ monitor.c | 31 +++---------------------------- qapi-schema.json | 22 ++++++++++++++++++++++ qmp-commands.hx | 6 ++++++ qmp.c | 28 ++++++++++++++++++++++++++++ 7 files changed, 108 insertions(+), 28 deletions(-) create mode 100644 hmp.c create mode 100644 hmp.h create mode 100644 qmp.c diff --git a/Makefile.objs b/Makefile.objs index 587ec3686..a669c62ce 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -407,6 +407,7 @@ qapi-nested-y += qmp-registry.o qmp-dispatch.o qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y)) common-obj-y += qmp-marshal.o qapi-visit.o qapi-types.o $(qapi-obj-y) +common-obj-y += qmp.o hmp.o ###################################################################### # guest agent diff --git a/hmp.c b/hmp.c new file mode 100644 index 000000000..47e1ff75c --- /dev/null +++ b/hmp.c @@ -0,0 +1,26 @@ +/* + * Human Monitor Interface + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "hmp.h" +#include "qmp-commands.h" + +void hmp_info_name(Monitor *mon) +{ + NameInfo *info; + + info = qmp_query_name(NULL); + if (info->has_name) { + monitor_printf(mon, "%s\n", info->name); + } + qapi_free_NameInfo(info); +} diff --git a/hmp.h b/hmp.h new file mode 100644 index 000000000..5fe73f1c5 --- /dev/null +++ b/hmp.h @@ -0,0 +1,22 @@ +/* + * Human Monitor Interface + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#ifndef HMP_H +#define HMP_H + +#include "qemu-common.h" +#include "qapi-types.h" + +void hmp_info_name(Monitor *mon); + +#endif diff --git a/monitor.c b/monitor.c index e267d5899..83b4fa71d 100644 --- a/monitor.c +++ b/monitor.c @@ -64,6 +64,8 @@ #include "trace/control.h" #include "ui/qemu-spice.h" #include "memory.h" +#include "qmp-commands.h" +#include "hmp.h" //#define DEBUG //#define DEBUG_COMPLETION @@ -760,24 +762,6 @@ static void do_info_version(Monitor *mon, QObject **ret_data) 'micro': %d }, 'package': %s }", major, minor, micro, QEMU_PKGVERSION); } -static void do_info_name_print(Monitor *mon, const QObject *data) -{ - QDict *qdict; - - qdict = qobject_to_qdict(data); - if (qdict_size(qdict) == 0) { - return; - } - - monitor_printf(mon, "%s\n", qdict_get_str(qdict, "name")); -} - -static void do_info_name(Monitor *mon, QObject **ret_data) -{ - *ret_data = qemu_name ? qobject_from_jsonf("{'name': %s }", qemu_name) : - qobject_from_jsonf("{}"); -} - static QObject *get_cmd_dict(const char *name) { const char *p; @@ -3094,8 +3078,7 @@ static const mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show the current VM name", - .user_print = do_info_name_print, - .mhandler.info_new = do_info_name, + .mhandler.info = hmp_info_name, }, { .name = "uuid", @@ -3286,14 +3269,6 @@ static const mon_cmd_t qmp_query_cmds[] = { .mhandler.info_new = do_info_spice, }, #endif - { - .name = "name", - .args_type = "", - .params = "", - .help = "show the current VM name", - .user_print = do_info_name_print, - .mhandler.info_new = do_info_name, - }, { .name = "uuid", .args_type = "", diff --git a/qapi-schema.json b/qapi-schema.json index 7fcefdb73..358532412 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1,3 +1,25 @@ # -*- Mode: Python -*- # # QAPI Schema + +## +# @NameInfo: +# +# Guest name information. +# +# @name: #optional The name of the guest +# +# Since 0.14.0 +## +{ 'type': 'NameInfo', 'data': {'*name': 'str'} } + +## +# @query-name: +# +# Return the name information of a guest. +# +# Returns: @NameInfo of the guest +# +# Since 0.14.0 +## +{ 'command': 'query-name', 'returns': 'NameInfo' } diff --git a/qmp-commands.hx b/qmp-commands.hx index d83bce566..7b3839ea1 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -1780,6 +1780,12 @@ Example: EQMP + { + .name = "query-name", + .args_type = "", + .mhandler.cmd_new = qmp_marshal_input_query_name, + }, + SQMP query-uuid ---------- diff --git a/qmp.c b/qmp.c new file mode 100644 index 000000000..8aa9c66bd --- /dev/null +++ b/qmp.c @@ -0,0 +1,28 @@ +/* + * QEMU Management Protocol + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "qemu-common.h" +#include "sysemu.h" +#include "qmp-commands.h" + +NameInfo *qmp_query_name(Error **errp) +{ + NameInfo *info = g_malloc0(sizeof(*info)); + + if (qemu_name) { + info->has_name = true; + info->name = g_strdup(qemu_name); + } + + return info; +} From b9c15f16d702306aeb984f30490cddb8b418a231 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 26 Aug 2011 17:38:13 -0300 Subject: [PATCH 14/26] qapi: Convert query-version Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- hmp.c | 13 +++++++++++++ hmp.h | 1 + monitor.c | 46 +++------------------------------------------- qapi-schema.json | 37 +++++++++++++++++++++++++++++++++++++ qmp-commands.hx | 6 ++++++ qmp.c | 16 ++++++++++++++++ 6 files changed, 76 insertions(+), 43 deletions(-) diff --git a/hmp.c b/hmp.c index 47e1ff75c..bb6c86f25 100644 --- a/hmp.c +++ b/hmp.c @@ -24,3 +24,16 @@ void hmp_info_name(Monitor *mon) } qapi_free_NameInfo(info); } + +void hmp_info_version(Monitor *mon) +{ + VersionInfo *info; + + info = qmp_query_version(NULL); + + monitor_printf(mon, "%" PRId64 ".%" PRId64 ".%" PRId64 "%s\n", + info->qemu.major, info->qemu.minor, info->qemu.micro, + info->package); + + qapi_free_VersionInfo(info); +} diff --git a/hmp.h b/hmp.h index 5fe73f1c5..2aa75a290 100644 --- a/hmp.h +++ b/hmp.h @@ -18,5 +18,6 @@ #include "qapi-types.h" void hmp_info_name(Monitor *mon); +void hmp_info_version(Monitor *mon); #endif diff --git a/monitor.c b/monitor.c index 83b4fa71d..483ea71d1 100644 --- a/monitor.c +++ b/monitor.c @@ -731,37 +731,6 @@ help: help_cmd(mon, "info"); } -static void do_info_version_print(Monitor *mon, const QObject *data) -{ - QDict *qdict; - QDict *qemu; - - qdict = qobject_to_qdict(data); - qemu = qdict_get_qdict(qdict, "qemu"); - - monitor_printf(mon, "%" PRId64 ".%" PRId64 ".%" PRId64 "%s\n", - qdict_get_int(qemu, "major"), - qdict_get_int(qemu, "minor"), - qdict_get_int(qemu, "micro"), - qdict_get_str(qdict, "package")); -} - -static void do_info_version(Monitor *mon, QObject **ret_data) -{ - const char *version = QEMU_VERSION; - int major = 0, minor = 0, micro = 0; - char *tmp; - - major = strtol(version, &tmp, 10); - tmp++; - minor = strtol(tmp, &tmp, 10); - tmp++; - micro = strtol(tmp, &tmp, 10); - - *ret_data = qobject_from_jsonf("{ 'qemu': { 'major': %d, 'minor': %d, \ - 'micro': %d }, 'package': %s }", major, minor, micro, QEMU_PKGVERSION); -} - static QObject *get_cmd_dict(const char *name) { const char *p; @@ -2872,8 +2841,7 @@ static const mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show the version of QEMU", - .user_print = do_info_version_print, - .mhandler.info_new = do_info_version, + .mhandler.info = hmp_info_version, }, { .name = "network", @@ -3171,14 +3139,6 @@ static const mon_cmd_t qmp_cmds[] = { }; static const mon_cmd_t qmp_query_cmds[] = { - { - .name = "version", - .args_type = "", - .params = "", - .help = "show the version of QEMU", - .user_print = do_info_version_print, - .mhandler.info_new = do_info_version, - }, { .name = "commands", .args_type = "", @@ -5185,9 +5145,9 @@ void monitor_resume(Monitor *mon) static QObject *get_qmp_greeting(void) { - QObject *ver; + QObject *ver = NULL; - do_info_version(NULL, &ver); + qmp_marshal_input_query_version(NULL, NULL, &ver); return qobject_from_jsonf("{'QMP':{'version': %p,'capabilities': []}}",ver); } diff --git a/qapi-schema.json b/qapi-schema.json index 358532412..3c0ac4e6e 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -23,3 +23,40 @@ # Since 0.14.0 ## { 'command': 'query-name', 'returns': 'NameInfo' } + +## +# @VersionInfo: +# +# A description of QEMU's version. +# +# @qemu.major: The major version of QEMU +# +# @qemu.minor: The minor version of QEMU +# +# @qemu.micro: The micro version of QEMU. By current convention, a micro +# version of 50 signifies a development branch. A micro version +# greater than or equal to 90 signifies a release candidate for +# the next minor version. A micro version of less than 50 +# signifies a stable release. +# +# @package: QEMU will always set this field to an empty string. Downstream +# versions of QEMU should set this to a non-empty string. The +# exact format depends on the downstream however it highly +# recommended that a unique name is used. +# +# Since: 0.14.0 +## +{ 'type': 'VersionInfo', + 'data': {'qemu': {'major': 'int', 'minor': 'int', 'micro': 'int'}, + 'package': 'str'} } + +## +# @query-version: +# +# Returns the current version of QEMU. +# +# Returns: A @VersionInfo object describing the current version of QEMU. +# +# Since: 0.14.0 +## +{ 'command': 'query-version', 'returns': 'VersionInfo' } diff --git a/qmp-commands.hx b/qmp-commands.hx index 7b3839ea1..9f067ea11 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -1053,6 +1053,12 @@ Example: EQMP + { + .name = "query-version", + .args_type = "", + .mhandler.cmd_new = qmp_marshal_input_query_version, + }, + SQMP query-commands -------------- diff --git a/qmp.c b/qmp.c index 8aa9c66bd..f978ea424 100644 --- a/qmp.c +++ b/qmp.c @@ -26,3 +26,19 @@ NameInfo *qmp_query_name(Error **errp) return info; } + +VersionInfo *qmp_query_version(Error **err) +{ + VersionInfo *info = g_malloc0(sizeof(*info)); + const char *version = QEMU_VERSION; + char *tmp; + + info->qemu.major = strtol(version, &tmp, 10); + tmp++; + info->qemu.minor = strtol(tmp, &tmp, 10); + tmp++; + info->qemu.micro = strtol(tmp, &tmp, 10); + info->package = g_strdup(QEMU_PKGVERSION); + + return info; +} From 292a26027c8567556795dde771e46d87306bd013 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Mon, 12 Sep 2011 15:10:53 -0300 Subject: [PATCH 15/26] qapi: Convert query-kvm Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- hmp.c | 16 ++++++++++++++++ hmp.h | 1 + monitor.c | 36 +----------------------------------- qapi-schema.json | 25 +++++++++++++++++++++++++ qmp-commands.hx | 6 ++++++ qmp.c | 13 +++++++++++++ 6 files changed, 62 insertions(+), 35 deletions(-) diff --git a/hmp.c b/hmp.c index bb6c86f25..94a7f7448 100644 --- a/hmp.c +++ b/hmp.c @@ -37,3 +37,19 @@ void hmp_info_version(Monitor *mon) qapi_free_VersionInfo(info); } + +void hmp_info_kvm(Monitor *mon) +{ + KvmInfo *info; + + info = qmp_query_kvm(NULL); + monitor_printf(mon, "kvm support: "); + if (info->present) { + monitor_printf(mon, "%s\n", info->enabled ? "enabled" : "disabled"); + } else { + monitor_printf(mon, "not compiled\n"); + } + + qapi_free_KvmInfo(info); +} + diff --git a/hmp.h b/hmp.h index 2aa75a290..a93ac1fe2 100644 --- a/hmp.h +++ b/hmp.h @@ -19,5 +19,6 @@ void hmp_info_name(Monitor *mon); void hmp_info_version(Monitor *mon); +void hmp_info_kvm(Monitor *mon); #endif diff --git a/monitor.c b/monitor.c index 483ea71d1..dad4221c4 100644 --- a/monitor.c +++ b/monitor.c @@ -2430,31 +2430,6 @@ static void do_info_mtree(Monitor *mon) mtree_info((fprintf_function)monitor_printf, mon); } -static void do_info_kvm_print(Monitor *mon, const QObject *data) -{ - QDict *qdict; - - qdict = qobject_to_qdict(data); - - monitor_printf(mon, "kvm support: "); - if (qdict_get_bool(qdict, "present")) { - monitor_printf(mon, "%s\n", qdict_get_bool(qdict, "enabled") ? - "enabled" : "disabled"); - } else { - monitor_printf(mon, "not compiled\n"); - } -} - -static void do_info_kvm(Monitor *mon, QObject **ret_data) -{ -#ifdef CONFIG_KVM - *ret_data = qobject_from_jsonf("{ 'enabled': %i, 'present': true }", - kvm_enabled()); -#else - *ret_data = qobject_from_jsonf("{ 'enabled': false, 'present': false }"); -#endif -} - static void do_info_numa(Monitor *mon) { int i; @@ -2955,8 +2930,7 @@ static const mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show KVM information", - .user_print = do_info_kvm_print, - .mhandler.info_new = do_info_kvm, + .mhandler.info = hmp_info_kvm, }, { .name = "numa", @@ -3187,14 +3161,6 @@ static const mon_cmd_t qmp_query_cmds[] = { .user_print = do_pci_info_print, .mhandler.info_new = do_pci_info, }, - { - .name = "kvm", - .args_type = "", - .params = "", - .help = "show KVM information", - .user_print = do_info_kvm_print, - .mhandler.info_new = do_info_kvm, - }, { .name = "status", .args_type = "", diff --git a/qapi-schema.json b/qapi-schema.json index 3c0ac4e6e..641f12da7 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -60,3 +60,28 @@ # Since: 0.14.0 ## { 'command': 'query-version', 'returns': 'VersionInfo' } + +## +# @KvmInfo: +# +# Information about support for KVM acceleration +# +# @enabled: true if KVM acceleration is active +# +# @present: true if KVM acceleration is built into this executable +# +# Since: 0.14.0 +## +{ 'type': 'KvmInfo', 'data': {'enabled': 'bool', 'present': 'bool'} } + +## +# @query-kvm: +# +# Returns information about KVM acceleration +# +# Returns: @KvmInfo +# +# Since: 0.14.0 +## +{ 'command': 'query-kvm', 'returns': 'KvmInfo' } + diff --git a/qmp-commands.hx b/qmp-commands.hx index 9f067ea11..9f9751d1c 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -1570,6 +1570,12 @@ Example: EQMP + { + .name = "query-kvm", + .args_type = "", + .mhandler.cmd_new = qmp_marshal_input_query_kvm, + }, + SQMP query-status ------------ diff --git a/qmp.c b/qmp.c index f978ea424..8f7f666bb 100644 --- a/qmp.c +++ b/qmp.c @@ -14,6 +14,8 @@ #include "qemu-common.h" #include "sysemu.h" #include "qmp-commands.h" +#include "kvm.h" +#include "arch_init.h" NameInfo *qmp_query_name(Error **errp) { @@ -42,3 +44,14 @@ VersionInfo *qmp_query_version(Error **err) return info; } + +KvmInfo *qmp_query_kvm(Error **errp) +{ + KvmInfo *info = g_malloc0(sizeof(*info)); + + info->enabled = kvm_enabled(); + info->present = kvm_available(); + + return info; +} + From 0d45b702918f855c24bfd13c0f91b31f89c2e097 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 30 Sep 2011 14:27:11 -0300 Subject: [PATCH 16/26] vl: Change qemu_vmstop_requested() to return a bool The stop reason is returned in the RunState argument. This is a preparation for a future commit which will convert the query-status command to the QAPI. Signed-off-by: Luiz Capitulino --- vl.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/vl.c b/vl.c index bd4a5ce8a..4db58bd97 100644 --- a/vl.c +++ b/vl.c @@ -1350,11 +1350,15 @@ static int qemu_debug_requested(void) return r; } -static RunState qemu_vmstop_requested(void) +static bool qemu_vmstop_requested(RunState *r) { - RunState s = vmstop_requested; - vmstop_requested = RSTATE_NO_STATE; - return s; + if (vmstop_requested != RSTATE_NO_STATE) { + *r = vmstop_requested; + vmstop_requested = RSTATE_NO_STATE; + return true; + } + + return false; } void qemu_register_reset(QEMUResetHandler *func, void *opaque) @@ -1567,7 +1571,7 @@ static void main_loop(void) #ifdef CONFIG_PROFILER int64_t ti; #endif - int r; + RunState r; qemu_main_loop_start(); @@ -1606,7 +1610,7 @@ static void main_loop(void) monitor_protocol_event(QEVENT_POWERDOWN, NULL); qemu_irq_raise(qemu_system_powerdown); } - if ((r = qemu_vmstop_requested())) { + if (qemu_vmstop_requested(&r)) { vm_stop(r); } } From c4d11e38bd475f33d5fa9ceba5292304727f3113 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 30 Sep 2011 14:40:07 -0300 Subject: [PATCH 17/26] RunState: Drop the RSTATE_NO_STATE value The QAPI framework won't generate it, so we need to get rid of it. In order to do that, this commit makes RSTATE_PRE_LAUNCH the initial state and change qemu_vmstop_requested() to use RSTATE_MAX. Signed-off-by: Luiz Capitulino --- sysemu.h | 1 - vl.c | 19 +++++++------------ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/sysemu.h b/sysemu.h index 43ff546f9..41ccc02d5 100644 --- a/sysemu.h +++ b/sysemu.h @@ -11,7 +11,6 @@ /* vl.c */ typedef enum { - RSTATE_NO_STATE, RSTATE_DEBUG, /* qemu is running under gdb */ RSTATE_IN_MIGRATE, /* paused waiting for an incoming migration */ RSTATE_PANICKED, /* paused due to an internal error */ diff --git a/vl.c b/vl.c index 4db58bd97..bc61494d7 100644 --- a/vl.c +++ b/vl.c @@ -323,7 +323,7 @@ static int default_driver_check(QemuOpts *opts, void *opaque) /***********************************************************/ /* QEMU state */ -static RunState current_run_state = RSTATE_NO_STATE; +static RunState current_run_state = RSTATE_PRE_LAUNCH; typedef struct { RunState from; @@ -332,10 +332,6 @@ typedef struct { static const RunStateTransition runstate_transitions_def[] = { /* from -> to */ - { RSTATE_NO_STATE, RSTATE_RUNNING }, - { RSTATE_NO_STATE, RSTATE_IN_MIGRATE }, - { RSTATE_NO_STATE, RSTATE_PRE_LAUNCH }, - { RSTATE_DEBUG, RSTATE_RUNNING }, { RSTATE_IN_MIGRATE, RSTATE_RUNNING }, @@ -350,6 +346,7 @@ static const RunStateTransition runstate_transitions_def[] = { { RSTATE_POST_MIGRATE, RSTATE_RUNNING }, { RSTATE_PRE_LAUNCH, RSTATE_RUNNING }, + { RSTATE_PRE_LAUNCH, RSTATE_IN_MIGRATE }, { RSTATE_PRE_LAUNCH, RSTATE_POST_MIGRATE }, { RSTATE_PRE_MIGRATE, RSTATE_RUNNING }, @@ -424,8 +421,7 @@ void runstate_set(RunState new_state) const char *runstate_as_string(void) { - assert(current_run_state > RSTATE_NO_STATE && - current_run_state < RSTATE_MAX); + assert(current_run_state < RSTATE_MAX); return runstate_name_tbl[current_run_state]; } @@ -1294,7 +1290,7 @@ static int shutdown_requested, shutdown_signal = -1; static pid_t shutdown_pid; static int powerdown_requested; static int debug_requested; -static RunState vmstop_requested = RSTATE_NO_STATE; +static RunState vmstop_requested = RSTATE_MAX; int qemu_shutdown_requested_get(void) { @@ -1350,11 +1346,12 @@ static int qemu_debug_requested(void) return r; } +/* We use RSTATE_MAX but any invalid value will do */ static bool qemu_vmstop_requested(RunState *r) { - if (vmstop_requested != RSTATE_NO_STATE) { + if (vmstop_requested < RSTATE_MAX) { *r = vmstop_requested; - vmstop_requested = RSTATE_NO_STATE; + vmstop_requested = RSTATE_MAX; return true; } @@ -3569,8 +3566,6 @@ int main(int argc, char **argv, char **envp) } } else if (autostart) { vm_start(); - } else { - runstate_set(RSTATE_PRE_LAUNCH); } os_setup_post(); From 0461d5a699cb8825039400b76839115e35b73d65 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 30 Sep 2011 14:45:27 -0300 Subject: [PATCH 18/26] RunState: Rename enum values as generated by the QAPI Next commit will convert the query-status command to use the RunState type as generated by the QAPI. In order to "transparently" replace the current enum by the QAPI one, we have to make some changes to some enum values. As the changes are simple renames, I'll do them in one shot. The changes are: - Rename the prefix from RSTATE_ to RUN_STATE_ - RUN_STATE_SAVEVM to RUN_STATE_SAVE_VM - RUN_STATE_IN_MIGRATE to RUN_STATE_INMIGRATE - RUN_STATE_PANICKED to RUN_STATE_INTERNAL_ERROR - RUN_STATE_POST_MIGRATE to RUN_STATE_POSTMIGRATE - RUN_STATE_PRE_LAUNCH to RUN_STATE_PRELAUNCH - RUN_STATE_PRE_MIGRATE to RUN_STATE_PREMIGRATE - RUN_STATE_RESTORE to RUN_STATE_RESTORE_VM - RUN_STATE_PRE_MIGRATE to RUN_STATE_FINISH_MIGRATE Signed-off-by: Luiz Capitulino --- gdbstub.c | 26 +++++------ hw/ide/core.c | 2 +- hw/scsi-disk.c | 2 +- hw/virtio-blk.c | 2 +- hw/watchdog.c | 2 +- kvm-all.c | 2 +- migration.c | 6 +-- monitor.c | 10 ++--- savevm.c | 4 +- sysemu.h | 28 ++++++------ vl.c | 116 ++++++++++++++++++++++++------------------------ 11 files changed, 100 insertions(+), 100 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 12dd100af..31ecad255 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -2385,7 +2385,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state) return; } switch (state) { - case RSTATE_DEBUG: + case RUN_STATE_DEBUG: if (env->watchpoint_hit) { switch (env->watchpoint_hit->flags & BP_MEM_ACCESS) { case BP_MEM_READ: @@ -2408,25 +2408,25 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state) tb_flush(env); ret = GDB_SIGNAL_TRAP; break; - case RSTATE_PAUSED: + case RUN_STATE_PAUSED: ret = GDB_SIGNAL_INT; break; - case RSTATE_SHUTDOWN: + case RUN_STATE_SHUTDOWN: ret = GDB_SIGNAL_QUIT; break; - case RSTATE_IO_ERROR: + case RUN_STATE_IO_ERROR: ret = GDB_SIGNAL_IO; break; - case RSTATE_WATCHDOG: + case RUN_STATE_WATCHDOG: ret = GDB_SIGNAL_ALRM; break; - case RSTATE_PANICKED: + case RUN_STATE_INTERNAL_ERROR: ret = GDB_SIGNAL_ABRT; break; - case RSTATE_SAVEVM: - case RSTATE_RESTORE: + case RUN_STATE_SAVE_VM: + case RUN_STATE_RESTORE_VM: return; - case RSTATE_PRE_MIGRATE: + case RUN_STATE_FINISH_MIGRATE: ret = GDB_SIGNAL_XCPU; break; default: @@ -2463,7 +2463,7 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...) gdb_current_syscall_cb = cb; s->state = RS_SYSCALL; #ifndef CONFIG_USER_ONLY - vm_stop(RSTATE_DEBUG); + vm_stop(RUN_STATE_DEBUG); #endif s->state = RS_IDLE; va_start(va, fmt); @@ -2537,7 +2537,7 @@ static void gdb_read_byte(GDBState *s, int ch) if (runstate_is_running()) { /* when the CPU is running, we cannot do anything except stop it when receiving a char */ - vm_stop(RSTATE_PAUSED); + vm_stop(RUN_STATE_PAUSED); } else #endif { @@ -2799,7 +2799,7 @@ static void gdb_chr_event(void *opaque, int event) { switch (event) { case CHR_EVENT_OPENED: - vm_stop(RSTATE_PAUSED); + vm_stop(RUN_STATE_PAUSED); gdb_has_xml = 0; break; default: @@ -2840,7 +2840,7 @@ static int gdb_monitor_write(CharDriverState *chr, const uint8_t *buf, int len) static void gdb_sigterm_handler(int signal) { if (runstate_is_running()) { - vm_stop(RSTATE_PAUSED); + vm_stop(RUN_STATE_PAUSED); } } #endif diff --git a/hw/ide/core.c b/hw/ide/core.c index 4e76fc78d..b71a356f3 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -527,7 +527,7 @@ static int ide_handle_rw_error(IDEState *s, int error, int op) s->bus->dma->ops->set_unit(s->bus->dma, s->unit); s->bus->error_status = op; bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read); - vm_stop(RSTATE_IO_ERROR); + vm_stop(RUN_STATE_IO_ERROR); } else { if (op & BM_STATUS_DMA_RETRY) { dma_buf_commit(s, 0); diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index e843f712c..4f681ef09 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -227,7 +227,7 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type) r->status |= SCSI_REQ_STATUS_RETRY | type; bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read); - vm_stop(RSTATE_IO_ERROR); + vm_stop(RUN_STATE_IO_ERROR); } else { switch (error) { case ENOMEM: diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index daa8e42be..03878bfc5 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -77,7 +77,7 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error, req->next = s->rq; s->rq = req; bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read); - vm_stop(RSTATE_IO_ERROR); + vm_stop(RUN_STATE_IO_ERROR); } else { virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR); bdrv_acct_done(s->bs, &req->acct); diff --git a/hw/watchdog.c b/hw/watchdog.c index 71c6c7df6..4c1896565 100644 --- a/hw/watchdog.c +++ b/hw/watchdog.c @@ -132,7 +132,7 @@ void watchdog_perform_action(void) case WDT_PAUSE: /* same as 'stop' command in monitor */ watchdog_mon_event("pause"); - vm_stop(RSTATE_WATCHDOG); + vm_stop(RUN_STATE_WATCHDOG); break; case WDT_DEBUG: diff --git a/kvm-all.c b/kvm-all.c index 228655b38..e7faf5cba 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -1014,7 +1014,7 @@ int kvm_cpu_exec(CPUState *env) if (ret < 0) { cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE); - vm_stop(RSTATE_PANICKED); + vm_stop(RUN_STATE_INTERNAL_ERROR); } env->exit_request = 0; diff --git a/migration.c b/migration.c index 7dd8f4eee..77a51adc5 100644 --- a/migration.c +++ b/migration.c @@ -73,7 +73,7 @@ void process_incoming_migration(QEMUFile *f) if (autostart) { vm_start(); } else { - runstate_set(RSTATE_PRE_LAUNCH); + runstate_set(RUN_STATE_PRELAUNCH); } } @@ -375,7 +375,7 @@ void migrate_fd_put_ready(void *opaque) int old_vm_running = runstate_is_running(); DPRINTF("done iterating\n"); - vm_stop(RSTATE_PRE_MIGRATE); + vm_stop(RUN_STATE_FINISH_MIGRATE); if ((qemu_savevm_state_complete(s->mon, s->file)) < 0) { if (old_vm_running) { @@ -392,7 +392,7 @@ void migrate_fd_put_ready(void *opaque) state = MIG_STATE_ERROR; } if (state == MIG_STATE_COMPLETED) { - runstate_set(RSTATE_POST_MIGRATE); + runstate_set(RUN_STATE_POSTMIGRATE); } s->state = state; notifier_list_notify(&migration_state_notifiers, NULL); diff --git a/monitor.c b/monitor.c index dad4221c4..da729cec2 100644 --- a/monitor.c +++ b/monitor.c @@ -1248,7 +1248,7 @@ static void do_singlestep(Monitor *mon, const QDict *qdict) */ static int do_stop(Monitor *mon, const QDict *qdict, QObject **ret_data) { - vm_stop(RSTATE_PAUSED); + vm_stop(RUN_STATE_PAUSED); return 0; } @@ -1266,11 +1266,11 @@ static int do_cont(Monitor *mon, const QDict *qdict, QObject **ret_data) { struct bdrv_iterate_context context = { mon, 0 }; - if (runstate_check(RSTATE_IN_MIGRATE)) { + if (runstate_check(RUN_STATE_INMIGRATE)) { qerror_report(QERR_MIGRATION_EXPECTED); return -1; - } else if (runstate_check(RSTATE_PANICKED) || - runstate_check(RSTATE_SHUTDOWN)) { + } else if (runstate_check(RUN_STATE_INTERNAL_ERROR) || + runstate_check(RUN_STATE_SHUTDOWN)) { qerror_report(QERR_RESET_REQUIRED); return -1; } @@ -2773,7 +2773,7 @@ static void do_loadvm(Monitor *mon, const QDict *qdict) int saved_vm_running = runstate_is_running(); const char *name = qdict_get_str(qdict, "name"); - vm_stop(RSTATE_RESTORE); + vm_stop(RUN_STATE_RESTORE_VM); if (load_vmstate(name) == 0 && saved_vm_running) { vm_start(); diff --git a/savevm.c b/savevm.c index 46f2447dc..bf4d0e76c 100644 --- a/savevm.c +++ b/savevm.c @@ -1603,7 +1603,7 @@ static int qemu_savevm_state(Monitor *mon, QEMUFile *f) int ret; saved_vm_running = runstate_is_running(); - vm_stop(RSTATE_SAVEVM); + vm_stop(RUN_STATE_SAVE_VM); if (qemu_savevm_state_blocked(mon)) { ret = -EINVAL; @@ -1932,7 +1932,7 @@ void do_savevm(Monitor *mon, const QDict *qdict) } saved_vm_running = runstate_is_running(); - vm_stop(RSTATE_SAVEVM); + vm_stop(RUN_STATE_SAVE_VM); memset(sn, 0, sizeof(*sn)); diff --git a/sysemu.h b/sysemu.h index 41ccc02d5..5d1fed2b2 100644 --- a/sysemu.h +++ b/sysemu.h @@ -11,20 +11,20 @@ /* vl.c */ typedef enum { - RSTATE_DEBUG, /* qemu is running under gdb */ - RSTATE_IN_MIGRATE, /* paused waiting for an incoming migration */ - RSTATE_PANICKED, /* paused due to an internal error */ - RSTATE_IO_ERROR, /* paused due to an I/O error */ - RSTATE_PAUSED, /* paused by the user (ie. the 'stop' command) */ - RSTATE_POST_MIGRATE, /* paused following a successful migration */ - RSTATE_PRE_LAUNCH, /* qemu was started with -S and haven't started */ - RSTATE_PRE_MIGRATE, /* paused preparing to finish migrate */ - RSTATE_RESTORE, /* paused restoring the VM state */ - RSTATE_RUNNING, /* qemu is running */ - RSTATE_SAVEVM, /* paused saving VM state */ - RSTATE_SHUTDOWN, /* guest shut down and -no-shutdown is in use */ - RSTATE_WATCHDOG, /* watchdog fired and qemu is configured to pause */ - RSTATE_MAX + RUN_STATE_DEBUG, /* qemu is running under gdb */ + RUN_STATE_INMIGRATE, /* paused waiting for an incoming migration */ + RUN_STATE_INTERNAL_ERROR, /* paused due to an internal error */ + RUN_STATE_IO_ERROR, /* paused due to an I/O error */ + RUN_STATE_PAUSED, /* paused by the user (ie. the 'stop' command) */ + RUN_STATE_POSTMIGRATE, /* paused following a successful migration */ + RUN_STATE_PRELAUNCH, /* qemu was started with -S and haven't started */ + RUN_STATE_FINISH_MIGRATE, /* paused preparing to finish migrate */ + RUN_STATE_RESTORE_VM, /* paused restoring the VM state */ + RUN_STATE_RUNNING, /* qemu is running */ + RUN_STATE_SAVE_VM, /* paused saving VM state */ + RUN_STATE_SHUTDOWN, /* guest shut down and -no-shutdown is in use */ + RUN_STATE_WATCHDOG, /* watchdog fired and qemu is configured to pause */ + RUN_STATE_MAX } RunState; extern const char *bios_name; diff --git a/vl.c b/vl.c index bc61494d7..ba4a151ad 100644 --- a/vl.c +++ b/vl.c @@ -323,7 +323,7 @@ static int default_driver_check(QemuOpts *opts, void *opaque) /***********************************************************/ /* QEMU state */ -static RunState current_run_state = RSTATE_PRE_LAUNCH; +static RunState current_run_state = RUN_STATE_PRELAUNCH; typedef struct { RunState from; @@ -332,63 +332,63 @@ typedef struct { static const RunStateTransition runstate_transitions_def[] = { /* from -> to */ - { RSTATE_DEBUG, RSTATE_RUNNING }, + { RUN_STATE_DEBUG, RUN_STATE_RUNNING }, - { RSTATE_IN_MIGRATE, RSTATE_RUNNING }, - { RSTATE_IN_MIGRATE, RSTATE_PRE_LAUNCH }, + { RUN_STATE_INMIGRATE, RUN_STATE_RUNNING }, + { RUN_STATE_INMIGRATE, RUN_STATE_PRELAUNCH }, - { RSTATE_PANICKED, RSTATE_PAUSED }, + { RUN_STATE_INTERNAL_ERROR, RUN_STATE_PAUSED }, - { RSTATE_IO_ERROR, RSTATE_RUNNING }, + { RUN_STATE_IO_ERROR, RUN_STATE_RUNNING }, - { RSTATE_PAUSED, RSTATE_RUNNING }, + { RUN_STATE_PAUSED, RUN_STATE_RUNNING }, - { RSTATE_POST_MIGRATE, RSTATE_RUNNING }, + { RUN_STATE_POSTMIGRATE, RUN_STATE_RUNNING }, - { RSTATE_PRE_LAUNCH, RSTATE_RUNNING }, - { RSTATE_PRE_LAUNCH, RSTATE_IN_MIGRATE }, - { RSTATE_PRE_LAUNCH, RSTATE_POST_MIGRATE }, + { RUN_STATE_PRELAUNCH, RUN_STATE_RUNNING }, + { RUN_STATE_PRELAUNCH, RUN_STATE_INMIGRATE }, + { RUN_STATE_PRELAUNCH, RUN_STATE_POSTMIGRATE }, - { RSTATE_PRE_MIGRATE, RSTATE_RUNNING }, - { RSTATE_PRE_MIGRATE, RSTATE_POST_MIGRATE }, + { RUN_STATE_FINISH_MIGRATE, RUN_STATE_RUNNING }, + { RUN_STATE_FINISH_MIGRATE, RUN_STATE_POSTMIGRATE }, - { RSTATE_RESTORE, RSTATE_RUNNING }, + { RUN_STATE_RESTORE_VM, RUN_STATE_RUNNING }, - { RSTATE_RUNNING, RSTATE_DEBUG }, - { RSTATE_RUNNING, RSTATE_PANICKED }, - { RSTATE_RUNNING, RSTATE_IO_ERROR }, - { RSTATE_RUNNING, RSTATE_PAUSED }, - { RSTATE_RUNNING, RSTATE_PRE_MIGRATE }, - { RSTATE_RUNNING, RSTATE_RESTORE }, - { RSTATE_RUNNING, RSTATE_SAVEVM }, - { RSTATE_RUNNING, RSTATE_SHUTDOWN }, - { RSTATE_RUNNING, RSTATE_WATCHDOG }, + { RUN_STATE_RUNNING, RUN_STATE_DEBUG }, + { RUN_STATE_RUNNING, RUN_STATE_INTERNAL_ERROR }, + { RUN_STATE_RUNNING, RUN_STATE_IO_ERROR }, + { RUN_STATE_RUNNING, RUN_STATE_PAUSED }, + { RUN_STATE_RUNNING, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_RUNNING, RUN_STATE_RESTORE_VM }, + { RUN_STATE_RUNNING, RUN_STATE_SAVE_VM }, + { RUN_STATE_RUNNING, RUN_STATE_SHUTDOWN }, + { RUN_STATE_RUNNING, RUN_STATE_WATCHDOG }, - { RSTATE_SAVEVM, RSTATE_RUNNING }, + { RUN_STATE_SAVE_VM, RUN_STATE_RUNNING }, - { RSTATE_SHUTDOWN, RSTATE_PAUSED }, + { RUN_STATE_SHUTDOWN, RUN_STATE_PAUSED }, - { RSTATE_WATCHDOG, RSTATE_RUNNING }, + { RUN_STATE_WATCHDOG, RUN_STATE_RUNNING }, - { RSTATE_MAX, RSTATE_MAX }, + { RUN_STATE_MAX, RUN_STATE_MAX }, }; -static bool runstate_valid_transitions[RSTATE_MAX][RSTATE_MAX]; +static bool runstate_valid_transitions[RUN_STATE_MAX][RUN_STATE_MAX]; -static const char *const runstate_name_tbl[RSTATE_MAX] = { - [RSTATE_DEBUG] = "debug", - [RSTATE_IN_MIGRATE] = "incoming-migration", - [RSTATE_PANICKED] = "internal-error", - [RSTATE_IO_ERROR] = "io-error", - [RSTATE_PAUSED] = "paused", - [RSTATE_POST_MIGRATE] = "post-migrate", - [RSTATE_PRE_LAUNCH] = "prelaunch", - [RSTATE_PRE_MIGRATE] = "finish-migrate", - [RSTATE_RESTORE] = "restore-vm", - [RSTATE_RUNNING] = "running", - [RSTATE_SAVEVM] = "save-vm", - [RSTATE_SHUTDOWN] = "shutdown", - [RSTATE_WATCHDOG] = "watchdog", +static const char *const runstate_name_tbl[RUN_STATE_MAX] = { + [RUN_STATE_DEBUG] = "debug", + [RUN_STATE_INMIGRATE] = "incoming-migration", + [RUN_STATE_INTERNAL_ERROR] = "internal-error", + [RUN_STATE_IO_ERROR] = "io-error", + [RUN_STATE_PAUSED] = "paused", + [RUN_STATE_POSTMIGRATE] = "post-migrate", + [RUN_STATE_PRELAUNCH] = "prelaunch", + [RUN_STATE_FINISH_MIGRATE] = "finish-migrate", + [RUN_STATE_RESTORE_VM] = "restore-vm", + [RUN_STATE_RUNNING] = "running", + [RUN_STATE_SAVE_VM] = "save-vm", + [RUN_STATE_SHUTDOWN] = "shutdown", + [RUN_STATE_WATCHDOG] = "watchdog", }; bool runstate_check(RunState state) @@ -402,7 +402,7 @@ void runstate_init(void) memset(&runstate_valid_transitions, 0, sizeof(runstate_valid_transitions)); - for (p = &runstate_transitions_def[0]; p->from != RSTATE_MAX; p++) { + for (p = &runstate_transitions_def[0]; p->from != RUN_STATE_MAX; p++) { runstate_valid_transitions[p->from][p->to] = true; } } @@ -410,7 +410,7 @@ void runstate_init(void) /* This function will abort() on invalid state transitions */ void runstate_set(RunState new_state) { - if (new_state >= RSTATE_MAX || + if (new_state >= RUN_STATE_MAX || !runstate_valid_transitions[current_run_state][new_state]) { fprintf(stderr, "invalid runstate transition\n"); abort(); @@ -421,13 +421,13 @@ void runstate_set(RunState new_state) const char *runstate_as_string(void) { - assert(current_run_state < RSTATE_MAX); + assert(current_run_state < RUN_STATE_MAX); return runstate_name_tbl[current_run_state]; } int runstate_is_running(void) { - return runstate_check(RSTATE_RUNNING); + return runstate_check(RUN_STATE_RUNNING); } /***********************************************************/ @@ -1268,8 +1268,8 @@ void vm_start(void) { if (!runstate_is_running()) { cpu_enable_ticks(); - runstate_set(RSTATE_RUNNING); - vm_state_notify(1, RSTATE_RUNNING); + runstate_set(RUN_STATE_RUNNING); + vm_state_notify(1, RUN_STATE_RUNNING); resume_all_vcpus(); monitor_protocol_event(QEVENT_RESUME, NULL); } @@ -1290,7 +1290,7 @@ static int shutdown_requested, shutdown_signal = -1; static pid_t shutdown_pid; static int powerdown_requested; static int debug_requested; -static RunState vmstop_requested = RSTATE_MAX; +static RunState vmstop_requested = RUN_STATE_MAX; int qemu_shutdown_requested_get(void) { @@ -1346,12 +1346,12 @@ static int qemu_debug_requested(void) return r; } -/* We use RSTATE_MAX but any invalid value will do */ +/* We use RUN_STATE_MAX but any invalid value will do */ static bool qemu_vmstop_requested(RunState *r) { - if (vmstop_requested < RSTATE_MAX) { + if (vmstop_requested < RUN_STATE_MAX) { *r = vmstop_requested; - vmstop_requested = RSTATE_MAX; + vmstop_requested = RUN_STATE_MAX; return true; } @@ -1583,13 +1583,13 @@ static void main_loop(void) #endif if (qemu_debug_requested()) { - vm_stop(RSTATE_DEBUG); + vm_stop(RUN_STATE_DEBUG); } if (qemu_shutdown_requested()) { qemu_kill_report(); monitor_protocol_event(QEVENT_SHUTDOWN, NULL); if (no_shutdown) { - vm_stop(RSTATE_SHUTDOWN); + vm_stop(RUN_STATE_SHUTDOWN); } else break; } @@ -1598,9 +1598,9 @@ static void main_loop(void) cpu_synchronize_all_states(); qemu_system_reset(VMRESET_REPORT); resume_all_vcpus(); - if (runstate_check(RSTATE_PANICKED) || - runstate_check(RSTATE_SHUTDOWN)) { - runstate_set(RSTATE_PAUSED); + if (runstate_check(RUN_STATE_INTERNAL_ERROR) || + runstate_check(RUN_STATE_SHUTDOWN)) { + runstate_set(RUN_STATE_PAUSED); } } if (qemu_powerdown_requested()) { @@ -3557,7 +3557,7 @@ int main(int argc, char **argv, char **envp) } if (incoming) { - runstate_set(RSTATE_IN_MIGRATE); + runstate_set(RUN_STATE_INMIGRATE); int ret = qemu_start_incoming_migration(incoming); if (ret < 0) { fprintf(stderr, "Migration failed. Exit code %s(%d), exiting.\n", From 1fa9a5e4aea36b4d21e42323ae43879c908af576 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Mon, 12 Sep 2011 17:54:20 -0300 Subject: [PATCH 19/26] qapi: Convert query-status Please, note that the RunState type as defined in sysemu.h and its runstate_as_string() function are being dropped in favor of the RunState type generated by the QAPI. Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- hmp.c | 19 ++++++++++++++ hmp.h | 1 + monitor.c | 41 +---------------------------- qapi-schema.json | 67 ++++++++++++++++++++++++++++++++++++++++++++++++ qmp-commands.hx | 6 +++++ sysemu.h | 19 +------------- vl.c | 34 +++++++++--------------- 7 files changed, 107 insertions(+), 80 deletions(-) diff --git a/hmp.c b/hmp.c index 94a7f7448..30925b037 100644 --- a/hmp.c +++ b/hmp.c @@ -53,3 +53,22 @@ void hmp_info_kvm(Monitor *mon) qapi_free_KvmInfo(info); } +void hmp_info_status(Monitor *mon) +{ + StatusInfo *info; + + info = qmp_query_status(NULL); + + monitor_printf(mon, "VM status: %s%s", + info->running ? "running" : "paused", + info->singlestep ? " (single step mode)" : ""); + + if (!info->running && info->status != RUN_STATE_PAUSED) { + monitor_printf(mon, " (%s)", RunState_lookup[info->status]); + } + + monitor_printf(mon, "\n"); + + qapi_free_StatusInfo(info); +} + diff --git a/hmp.h b/hmp.h index a93ac1fe2..df4242f33 100644 --- a/hmp.h +++ b/hmp.h @@ -20,5 +20,6 @@ void hmp_info_name(Monitor *mon); void hmp_info_version(Monitor *mon); void hmp_info_kvm(Monitor *mon); +void hmp_info_status(Monitor *mon); #endif diff --git a/monitor.c b/monitor.c index da729cec2..e68f2e272 100644 --- a/monitor.c +++ b/monitor.c @@ -2550,36 +2550,6 @@ static int do_inject_nmi(Monitor *mon, const QDict *qdict, QObject **ret_data) } #endif -static void do_info_status_print(Monitor *mon, const QObject *data) -{ - QDict *qdict; - const char *status; - - qdict = qobject_to_qdict(data); - - monitor_printf(mon, "VM status: "); - if (qdict_get_bool(qdict, "running")) { - monitor_printf(mon, "running"); - if (qdict_get_bool(qdict, "singlestep")) { - monitor_printf(mon, " (single step mode)"); - } - } else { - monitor_printf(mon, "paused"); - } - - status = qdict_get_str(qdict, "status"); - if (strcmp(status, "paused") && strcmp(status, "running")) { - monitor_printf(mon, " (%s)", status); - } - - monitor_printf(mon, "\n"); -} - -static void do_info_status(Monitor *mon, QObject **ret_data) -{ - *ret_data = qobject_from_jsonf("{ 'running': %i, 'singlestep': %i, 'status': %s }", runstate_is_running(), singlestep, runstate_as_string()); -} - static qemu_acl *find_acl(Monitor *mon, const char *name) { qemu_acl *acl = qemu_acl_find(name); @@ -2979,8 +2949,7 @@ static const mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show the current VM status (running|paused)", - .user_print = do_info_status_print, - .mhandler.info_new = do_info_status, + .mhandler.info = hmp_info_status, }, { .name = "pcmcia", @@ -3161,14 +3130,6 @@ static const mon_cmd_t qmp_query_cmds[] = { .user_print = do_pci_info_print, .mhandler.info_new = do_pci_info, }, - { - .name = "status", - .args_type = "", - .params = "", - .help = "show the current VM status (running|paused)", - .user_print = do_info_status_print, - .mhandler.info_new = do_info_status, - }, { .name = "mice", .args_type = "", diff --git a/qapi-schema.json b/qapi-schema.json index 641f12da7..0e59c7100 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -85,3 +85,70 @@ ## { 'command': 'query-kvm', 'returns': 'KvmInfo' } +## +# @RunState +# +# An enumation of VM run states. +# +# @debug: QEMU is running on a debugger +# +# @inmigrate: guest is paused waiting for an incoming migration +# +# @internal-error: An internal error that prevents further guest execution +# has occurred +# +# @io-error: the last IOP has failed and the device is configured to pause +# on I/O errors +# +# @paused: guest has been paused via the 'stop' command +# +# @postmigrate: guest is paused following a successful 'migrate' +# +# @prelaunch: QEMU was started with -S and guest has not started +# +# @finish-migrate: guest is paused to finish the migration process +# +# @restore-vm: guest is paused to restore VM state +# +# @running: guest is actively running +# +# @save-vm: guest is paused to save the VM state +# +# @shutdown: guest is shut down (and -no-shutdown is in use) +# +# @watchdog: the watchdog action is configured to pause and has been triggered +## +{ 'enum': 'RunState', + 'data': [ 'debug', 'inmigrate', 'internal-error', 'io-error', 'paused', + 'postmigrate', 'prelaunch', 'finish-migrate', 'restore-vm', + 'running', 'save-vm', 'shutdown', 'watchdog' ] } + +## +# @StatusInfo: +# +# Information about VCPU run state +# +# @running: true if all VCPUs are runnable, false if not runnable +# +# @singlestep: true if VCPUs are in single-step mode +# +# @status: the virtual machine @RunState +# +# Since: 0.14.0 +# +# Notes: @singlestep is enabled through the GDB stub +## +{ 'type': 'StatusInfo', + 'data': {'running': 'bool', 'singlestep': 'bool', 'status': 'RunState'} } + +## +# @query-status: +# +# Query the run status of all VCPUs +# +# Returns: @StatusInfo reflecting all VCPUs +# +# Since: 0.14.0 +## +{ 'command': 'query-status', 'returns': 'StatusInfo' } + diff --git a/qmp-commands.hx b/qmp-commands.hx index 9f9751d1c..afa95bd93 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -1609,6 +1609,12 @@ Example: <- { "return": { "running": true, "singlestep": false, "status": "running" } } EQMP + + { + .name = "query-status", + .args_type = "", + .mhandler.cmd_new = qmp_marshal_input_query_status, + }, SQMP query-mice diff --git a/sysemu.h b/sysemu.h index 5d1fed2b2..a889d9095 100644 --- a/sysemu.h +++ b/sysemu.h @@ -6,27 +6,11 @@ #include "qemu-option.h" #include "qemu-queue.h" #include "qemu-timer.h" +#include "qapi-types.h" #include "notify.h" /* vl.c */ -typedef enum { - RUN_STATE_DEBUG, /* qemu is running under gdb */ - RUN_STATE_INMIGRATE, /* paused waiting for an incoming migration */ - RUN_STATE_INTERNAL_ERROR, /* paused due to an internal error */ - RUN_STATE_IO_ERROR, /* paused due to an I/O error */ - RUN_STATE_PAUSED, /* paused by the user (ie. the 'stop' command) */ - RUN_STATE_POSTMIGRATE, /* paused following a successful migration */ - RUN_STATE_PRELAUNCH, /* qemu was started with -S and haven't started */ - RUN_STATE_FINISH_MIGRATE, /* paused preparing to finish migrate */ - RUN_STATE_RESTORE_VM, /* paused restoring the VM state */ - RUN_STATE_RUNNING, /* qemu is running */ - RUN_STATE_SAVE_VM, /* paused saving VM state */ - RUN_STATE_SHUTDOWN, /* guest shut down and -no-shutdown is in use */ - RUN_STATE_WATCHDOG, /* watchdog fired and qemu is configured to pause */ - RUN_STATE_MAX -} RunState; - extern const char *bios_name; extern const char *qemu_name; @@ -38,7 +22,6 @@ void runstate_init(void); bool runstate_check(RunState state); void runstate_set(RunState new_state); int runstate_is_running(void); -const char *runstate_as_string(void); typedef struct vm_change_state_entry VMChangeStateEntry; typedef void VMChangeStateHandler(void *opaque, int running, RunState state); diff --git a/vl.c b/vl.c index ba4a151ad..dbf77781a 100644 --- a/vl.c +++ b/vl.c @@ -147,6 +147,7 @@ int main(int argc, char **argv) #include "qemu-config.h" #include "qemu-objects.h" #include "qemu-options.h" +#include "qmp-commands.h" #ifdef CONFIG_VIRTFS #include "fsdev/qemu-fsdev.h" #endif @@ -375,22 +376,6 @@ static const RunStateTransition runstate_transitions_def[] = { static bool runstate_valid_transitions[RUN_STATE_MAX][RUN_STATE_MAX]; -static const char *const runstate_name_tbl[RUN_STATE_MAX] = { - [RUN_STATE_DEBUG] = "debug", - [RUN_STATE_INMIGRATE] = "incoming-migration", - [RUN_STATE_INTERNAL_ERROR] = "internal-error", - [RUN_STATE_IO_ERROR] = "io-error", - [RUN_STATE_PAUSED] = "paused", - [RUN_STATE_POSTMIGRATE] = "post-migrate", - [RUN_STATE_PRELAUNCH] = "prelaunch", - [RUN_STATE_FINISH_MIGRATE] = "finish-migrate", - [RUN_STATE_RESTORE_VM] = "restore-vm", - [RUN_STATE_RUNNING] = "running", - [RUN_STATE_SAVE_VM] = "save-vm", - [RUN_STATE_SHUTDOWN] = "shutdown", - [RUN_STATE_WATCHDOG] = "watchdog", -}; - bool runstate_check(RunState state) { return current_run_state == state; @@ -419,17 +404,22 @@ void runstate_set(RunState new_state) current_run_state = new_state; } -const char *runstate_as_string(void) -{ - assert(current_run_state < RUN_STATE_MAX); - return runstate_name_tbl[current_run_state]; -} - int runstate_is_running(void) { return runstate_check(RUN_STATE_RUNNING); } +StatusInfo *qmp_query_status(Error **errp) +{ + StatusInfo *info = g_malloc0(sizeof(*info)); + + info->running = runstate_is_running(); + info->singlestep = singlestep; + info->status = current_run_state; + + return info; +} + /***********************************************************/ /* real time host monotonic timer */ From efab767eaafe39a234e8244819d0969ff59a325a Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Tue, 13 Sep 2011 17:16:25 -0300 Subject: [PATCH 20/26] qapi: Convert query-uuid Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- hmp.c | 8 ++++++++ hmp.h | 1 + monitor.c | 28 +--------------------------- qapi-schema.json | 24 ++++++++++++++++++++++++ qmp-commands.hx | 6 ++++++ qmp.c | 15 +++++++++++++++ 6 files changed, 55 insertions(+), 27 deletions(-) diff --git a/hmp.c b/hmp.c index 30925b037..25302f571 100644 --- a/hmp.c +++ b/hmp.c @@ -72,3 +72,11 @@ void hmp_info_status(Monitor *mon) qapi_free_StatusInfo(info); } +void hmp_info_uuid(Monitor *mon) +{ + UuidInfo *info; + + info = qmp_query_uuid(NULL); + monitor_printf(mon, "%s\n", info->UUID); + qapi_free_UuidInfo(info); +} diff --git a/hmp.h b/hmp.h index df4242f33..49a59712d 100644 --- a/hmp.h +++ b/hmp.h @@ -21,5 +21,6 @@ void hmp_info_name(Monitor *mon); void hmp_info_version(Monitor *mon); void hmp_info_kvm(Monitor *mon); void hmp_info_status(Monitor *mon); +void hmp_info_uuid(Monitor *mon); #endif diff --git a/monitor.c b/monitor.c index e68f2e272..4e9ecdfea 100644 --- a/monitor.c +++ b/monitor.c @@ -766,23 +766,6 @@ static void do_info_commands(Monitor *mon, QObject **ret_data) *ret_data = QOBJECT(cmd_list); } -static void do_info_uuid_print(Monitor *mon, const QObject *data) -{ - monitor_printf(mon, "%s\n", qdict_get_str(qobject_to_qdict(data), "UUID")); -} - -static void do_info_uuid(Monitor *mon, QObject **ret_data) -{ - char uuid[64]; - - snprintf(uuid, sizeof(uuid), UUID_FMT, qemu_uuid[0], qemu_uuid[1], - qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], qemu_uuid[5], - qemu_uuid[6], qemu_uuid[7], qemu_uuid[8], qemu_uuid[9], - qemu_uuid[10], qemu_uuid[11], qemu_uuid[12], qemu_uuid[13], - qemu_uuid[14], qemu_uuid[15]); - *ret_data = qobject_from_jsonf("{ 'UUID': %s }", uuid); -} - /* get the current CPU defined by the user */ static int mon_set_cpu(int cpu_index) { @@ -2996,8 +2979,7 @@ static const mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show the current VM UUID", - .user_print = do_info_uuid_print, - .mhandler.info_new = do_info_uuid, + .mhandler.info = hmp_info_uuid, }, #if defined(TARGET_PPC) { @@ -3156,14 +3138,6 @@ static const mon_cmd_t qmp_query_cmds[] = { .mhandler.info_new = do_info_spice, }, #endif - { - .name = "uuid", - .args_type = "", - .params = "", - .help = "show the current VM UUID", - .user_print = do_info_uuid_print, - .mhandler.info_new = do_info_uuid, - }, { .name = "migrate", .args_type = "", diff --git a/qapi-schema.json b/qapi-schema.json index 0e59c7100..b717491bb 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -152,3 +152,27 @@ ## { 'command': 'query-status', 'returns': 'StatusInfo' } +## +# @UuidInfo: +# +# Guest UUID information. +# +# @UUID: the UUID of the guest +# +# Since: 0.14.0 +# +# Notes: If no UUID was specified for the guest, a null UUID is returned. +## +{ 'type': 'UuidInfo', 'data': {'UUID': 'str'} } + +## +# @query-uuid: +# +# Query the guest UUID information. +# +# Returns: The @UuidInfo for the guest +# +# Since 0.14.0 +## +{ 'command': 'query-uuid', 'returns': 'UuidInfo' } + diff --git a/qmp-commands.hx b/qmp-commands.hx index afa95bd93..4fef25f4c 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -1821,6 +1821,12 @@ Example: EQMP + { + .name = "query-uuid", + .args_type = "", + .mhandler.cmd_new = qmp_marshal_input_query_uuid, + }, + SQMP query-migrate ------------- diff --git a/qmp.c b/qmp.c index 8f7f666bb..58337c79f 100644 --- a/qmp.c +++ b/qmp.c @@ -55,3 +55,18 @@ KvmInfo *qmp_query_kvm(Error **errp) return info; } +UuidInfo *qmp_query_uuid(Error **errp) +{ + UuidInfo *info = g_malloc0(sizeof(*info)); + char uuid[64]; + + snprintf(uuid, sizeof(uuid), UUID_FMT, qemu_uuid[0], qemu_uuid[1], + qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], qemu_uuid[5], + qemu_uuid[6], qemu_uuid[7], qemu_uuid[8], qemu_uuid[9], + qemu_uuid[10], qemu_uuid[11], qemu_uuid[12], qemu_uuid[13], + qemu_uuid[14], qemu_uuid[15]); + + info->UUID = g_strdup(uuid); + return info; +} + From c5a415a0afddbc217263b62a8e87d8ec9e7f760f Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 14 Sep 2011 16:05:49 -0300 Subject: [PATCH 21/26] qapi: Convert query-chardev Reviewed-by: Michael Roth Tested-by: Michael Roth Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- hmp.c | 13 +++++++++++++ hmp.h | 1 + monitor.c | 11 +---------- qapi-schema.json | 26 ++++++++++++++++++++++++++ qemu-char.c | 35 +++++++++++------------------------ qmp-commands.hx | 6 ++++++ 6 files changed, 58 insertions(+), 34 deletions(-) diff --git a/hmp.c b/hmp.c index 25302f571..30c6cc951 100644 --- a/hmp.c +++ b/hmp.c @@ -80,3 +80,16 @@ void hmp_info_uuid(Monitor *mon) monitor_printf(mon, "%s\n", info->UUID); qapi_free_UuidInfo(info); } + +void hmp_info_chardev(Monitor *mon) +{ + ChardevInfoList *char_info, *info; + + char_info = qmp_query_chardev(NULL); + for (info = char_info; info; info = info->next) { + monitor_printf(mon, "%s: filename=%s\n", info->value->label, + info->value->filename); + } + + qapi_free_ChardevInfoList(char_info); +} diff --git a/hmp.h b/hmp.h index 49a59712d..7388f9a6e 100644 --- a/hmp.h +++ b/hmp.h @@ -22,5 +22,6 @@ void hmp_info_version(Monitor *mon); void hmp_info_kvm(Monitor *mon); void hmp_info_status(Monitor *mon); void hmp_info_uuid(Monitor *mon); +void hmp_info_chardev(Monitor *mon); #endif diff --git a/monitor.c b/monitor.c index 4e9ecdfea..86a0dad2c 100644 --- a/monitor.c +++ b/monitor.c @@ -2783,8 +2783,7 @@ static const mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show the character devices", - .user_print = qemu_chr_info_print, - .mhandler.info_new = qemu_chr_info, + .mhandler.info = hmp_info_chardev, }, { .name = "block", @@ -3072,14 +3071,6 @@ static const mon_cmd_t qmp_query_cmds[] = { .user_print = monitor_user_noop, .mhandler.info_new = do_info_commands, }, - { - .name = "chardev", - .args_type = "", - .params = "", - .help = "show the character devices", - .user_print = qemu_chr_info_print, - .mhandler.info_new = qemu_chr_info, - }, { .name = "block", .args_type = "", diff --git a/qapi-schema.json b/qapi-schema.json index b717491bb..cf5550437 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -176,3 +176,29 @@ ## { 'command': 'query-uuid', 'returns': 'UuidInfo' } +## +# @ChardevInfo: +# +# Information about a character device. +# +# @label: the label of the character device +# +# @filename: the filename of the character device +# +# Notes: @filename is encoded using the QEMU command line character device +# encoding. See the QEMU man page for details. +# +# Since: 0.14.0 +## +{ 'type': 'ChardevInfo', 'data': {'label': 'str', 'filename': 'str'} } + +## +# @query-chardev: +# +# Returns information about current character devices. +# +# Returns: a list of @ChardevInfo +# +# Since: 0.14.0 +## +{ 'command': 'query-chardev', 'returns': ['ChardevInfo'] } diff --git a/qemu-char.c b/qemu-char.c index 09d2309eb..8bdbcfdad 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -31,7 +31,7 @@ #include "hw/usb.h" #include "hw/baum.h" #include "hw/msmouse.h" -#include "qemu-objects.h" +#include "qmp-commands.h" #include #include @@ -2650,35 +2650,22 @@ void qemu_chr_delete(CharDriverState *chr) g_free(chr); } -static void qemu_chr_qlist_iter(QObject *obj, void *opaque) +ChardevInfoList *qmp_query_chardev(Error **errp) { - QDict *chr_dict; - Monitor *mon = opaque; - - chr_dict = qobject_to_qdict(obj); - monitor_printf(mon, "%s: filename=%s\n", qdict_get_str(chr_dict, "label"), - qdict_get_str(chr_dict, "filename")); -} - -void qemu_chr_info_print(Monitor *mon, const QObject *ret_data) -{ - qlist_iter(qobject_to_qlist(ret_data), qemu_chr_qlist_iter, mon); -} - -void qemu_chr_info(Monitor *mon, QObject **ret_data) -{ - QList *chr_list; + ChardevInfoList *chr_list = NULL; CharDriverState *chr; - chr_list = qlist_new(); - QTAILQ_FOREACH(chr, &chardevs, next) { - QObject *obj = qobject_from_jsonf("{ 'label': %s, 'filename': %s }", - chr->label, chr->filename); - qlist_append_obj(chr_list, obj); + ChardevInfoList *info = g_malloc0(sizeof(*info)); + info->value = g_malloc0(sizeof(*info->value)); + info->value->label = g_strdup(chr->label); + info->value->filename = g_strdup(chr->filename); + + info->next = chr_list; + chr_list = info; } - *ret_data = QOBJECT(chr_list); + return chr_list; } CharDriverState *qemu_chr_find(const char *name) diff --git a/qmp-commands.hx b/qmp-commands.hx index 4fef25f4c..dfc02af37 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -1120,6 +1120,12 @@ Example: EQMP + { + .name = "query-chardev", + .args_type = "", + .mhandler.cmd_new = qmp_marshal_input_query_chardev, + }, + SQMP query-block ----------- From aa9b79bcd813b399ad13e13b5db4e8b2e8787e4c Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 21 Sep 2011 14:31:51 -0300 Subject: [PATCH 22/26] qapi: Convert query-commands Signed-off-by: Luiz Capitulino --- monitor.c | 40 +++++++++++++++------------------------- qapi-schema.json | 23 +++++++++++++++++++++++ qmp-commands.hx | 6 ++++++ 3 files changed, 44 insertions(+), 25 deletions(-) diff --git a/monitor.c b/monitor.c index 86a0dad2c..0c90506cd 100644 --- a/monitor.c +++ b/monitor.c @@ -731,39 +731,37 @@ help: help_cmd(mon, "info"); } -static QObject *get_cmd_dict(const char *name) +static CommandInfoList *alloc_cmd_entry(const char *cmd_name) { - const char *p; + CommandInfoList *info; - /* Remove '|' from some commands */ - p = strchr(name, '|'); - if (p) { - p++; - } else { - p = name; - } + info = g_malloc0(sizeof(*info)); + info->value = g_malloc0(sizeof(*info->value)); + info->value->name = g_strdup(cmd_name); - return qobject_from_jsonf("{ 'name': %s }", p); + return info; } -static void do_info_commands(Monitor *mon, QObject **ret_data) +CommandInfoList *qmp_query_commands(Error **errp) { - QList *cmd_list; + CommandInfoList *info, *cmd_list = NULL; const mon_cmd_t *cmd; - cmd_list = qlist_new(); - for (cmd = qmp_cmds; cmd->name != NULL; cmd++) { - qlist_append_obj(cmd_list, get_cmd_dict(cmd->name)); + info = alloc_cmd_entry(cmd->name); + info->next = cmd_list; + cmd_list = info; } for (cmd = qmp_query_cmds; cmd->name != NULL; cmd++) { char buf[128]; snprintf(buf, sizeof(buf), "query-%s", cmd->name); - qlist_append_obj(cmd_list, get_cmd_dict(buf)); + info = alloc_cmd_entry(buf); + info->next = cmd_list; + cmd_list = info; } - *ret_data = QOBJECT(cmd_list); + return cmd_list; } /* get the current CPU defined by the user */ @@ -3063,14 +3061,6 @@ static const mon_cmd_t qmp_cmds[] = { }; static const mon_cmd_t qmp_query_cmds[] = { - { - .name = "commands", - .args_type = "", - .params = "", - .help = "list QMP available commands", - .user_print = monitor_user_noop, - .mhandler.info_new = do_info_commands, - }, { .name = "block", .args_type = "", diff --git a/qapi-schema.json b/qapi-schema.json index cf5550437..35434c1eb 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -202,3 +202,26 @@ # Since: 0.14.0 ## { 'command': 'query-chardev', 'returns': ['ChardevInfo'] } + +## +# @CommandInfo: +# +# Information about a QMP command +# +# @name: The command name +# +# Since: 0.14.0 +## +{ 'type': 'CommandInfo', 'data': {'name': 'str'} } + +## +# @query-commands: +# +# Return a list of supported QMP commands by this server +# +# Returns: A list of @CommandInfo for all supported commands +# +# Since: 0.14.0 +## +{ 'command': 'query-commands', 'returns': ['CommandInfo'] } + diff --git a/qmp-commands.hx b/qmp-commands.hx index dfc02af37..0fda5c3b9 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -1090,6 +1090,12 @@ Note: This example has been shortened as the real response is too long. EQMP + { + .name = "query-commands", + .args_type = "", + .mhandler.cmd_new = qmp_marshal_input_query_commands, + }, + SQMP query-chardev ------------- From 7a7f325e053c5079ce4b7b8e9e2b0f4c4c30ade8 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 15 Sep 2011 14:20:28 -0300 Subject: [PATCH 23/26] qapi: Convert quit Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- hmp-commands.hx | 2 +- hmp.c | 6 ++++++ hmp.h | 1 + monitor.c | 12 ------------ qapi-schema.json | 11 +++++++++++ qmp-commands.hx | 5 +---- qmp.c | 6 ++++++ 7 files changed, 26 insertions(+), 17 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index 9e1cca8e3..2163e6f5f 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -43,7 +43,7 @@ ETEXI .params = "", .help = "quit the emulator", .user_print = monitor_user_noop, - .mhandler.cmd_new = do_quit, + .mhandler.cmd = hmp_quit, }, STEXI diff --git a/hmp.c b/hmp.c index 30c6cc951..7695dfc46 100644 --- a/hmp.c +++ b/hmp.c @@ -93,3 +93,9 @@ void hmp_info_chardev(Monitor *mon) qapi_free_ChardevInfoList(char_info); } + +void hmp_quit(Monitor *mon, const QDict *qdict) +{ + monitor_suspend(mon); + qmp_quit(NULL); +} diff --git a/hmp.h b/hmp.h index 7388f9a6e..a3dfafd8e 100644 --- a/hmp.h +++ b/hmp.h @@ -23,5 +23,6 @@ void hmp_info_kvm(Monitor *mon); void hmp_info_status(Monitor *mon); void hmp_info_uuid(Monitor *mon); void hmp_info_chardev(Monitor *mon); +void hmp_quit(Monitor *mon, const QDict *qdict); #endif diff --git a/monitor.c b/monitor.c index 0c90506cd..6e13ef657 100644 --- a/monitor.c +++ b/monitor.c @@ -946,18 +946,6 @@ static void do_trace_print_events(Monitor *mon) trace_print_events((FILE *)mon, &monitor_fprintf); } -/** - * do_quit(): Quit QEMU execution - */ -static int do_quit(Monitor *mon, const QDict *qdict, QObject **ret_data) -{ - monitor_suspend(mon); - no_shutdown = 0; - qemu_system_shutdown_request(); - - return 0; -} - #ifdef CONFIG_VNC static int change_vnc_password(const char *password) { diff --git a/qapi-schema.json b/qapi-schema.json index 35434c1eb..38104635c 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -225,3 +225,14 @@ ## { 'command': 'query-commands', 'returns': ['CommandInfo'] } +## +# @quit: +# +# This command will cause the QEMU process to exit gracefully. While every +# attempt is made to send the QMP response before terminating, this is not +# guaranteed. When using this interface, a premature EOF would not be +# unexpected. +# +# Since: 0.14.0 +## +{ 'command': 'quit' } diff --git a/qmp-commands.hx b/qmp-commands.hx index 0fda5c3b9..151a5fa65 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -63,10 +63,7 @@ EQMP { .name = "quit", .args_type = "", - .params = "", - .help = "quit the emulator", - .user_print = monitor_user_noop, - .mhandler.cmd_new = do_quit, + .mhandler.cmd_new = qmp_marshal_input_quit, }, SQMP diff --git a/qmp.c b/qmp.c index 58337c79f..1d380b6a5 100644 --- a/qmp.c +++ b/qmp.c @@ -70,3 +70,9 @@ UuidInfo *qmp_query_uuid(Error **errp) return info; } +void qmp_quit(Error **err) +{ + no_shutdown = 0; + qemu_system_shutdown_request(); +} + From 5f158f21f9b2ff129b5154bccf6212692ac9f6c1 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 15 Sep 2011 14:34:39 -0300 Subject: [PATCH 24/26] qapi: Convert stop Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- hmp-commands.hx | 3 +-- hmp.c | 5 +++++ hmp.h | 1 + monitor.c | 9 --------- qapi-schema.json | 12 ++++++++++++ qmp-commands.hx | 5 +---- qmp.c | 5 +++++ 7 files changed, 25 insertions(+), 15 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index 2163e6f5f..3ad1ce7df 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -290,8 +290,7 @@ ETEXI .args_type = "", .params = "", .help = "stop emulation", - .user_print = monitor_user_noop, - .mhandler.cmd_new = do_stop, + .mhandler.cmd = hmp_stop, }, STEXI diff --git a/hmp.c b/hmp.c index 7695dfc46..efcb74456 100644 --- a/hmp.c +++ b/hmp.c @@ -99,3 +99,8 @@ void hmp_quit(Monitor *mon, const QDict *qdict) monitor_suspend(mon); qmp_quit(NULL); } + +void hmp_stop(Monitor *mon, const QDict *qdict) +{ + qmp_stop(NULL); +} diff --git a/hmp.h b/hmp.h index a3dfafd8e..cb21ccea9 100644 --- a/hmp.h +++ b/hmp.h @@ -24,5 +24,6 @@ void hmp_info_status(Monitor *mon); void hmp_info_uuid(Monitor *mon); void hmp_info_chardev(Monitor *mon); void hmp_quit(Monitor *mon, const QDict *qdict); +void hmp_stop(Monitor *mon, const QDict *qdict); #endif diff --git a/monitor.c b/monitor.c index 6e13ef657..2a5230caa 100644 --- a/monitor.c +++ b/monitor.c @@ -1212,15 +1212,6 @@ static void do_singlestep(Monitor *mon, const QDict *qdict) } } -/** - * do_stop(): Stop VM execution - */ -static int do_stop(Monitor *mon, const QDict *qdict, QObject **ret_data) -{ - vm_stop(RUN_STATE_PAUSED); - return 0; -} - static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs); struct bdrv_iterate_context { diff --git a/qapi-schema.json b/qapi-schema.json index 38104635c..cd0503495 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -236,3 +236,15 @@ # Since: 0.14.0 ## { 'command': 'quit' } + +## +# @stop: +# +# Stop all guest VCPU execution. +# +# Since: 0.14.0 +# +# Notes: This function will succeed even if the guest is already in the stopped +# state +## +{ 'command': 'stop' } diff --git a/qmp-commands.hx b/qmp-commands.hx index 151a5fa65..2ccddeed2 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -178,10 +178,7 @@ EQMP { .name = "stop", .args_type = "", - .params = "", - .help = "stop emulation", - .user_print = monitor_user_noop, - .mhandler.cmd_new = do_stop, + .mhandler.cmd_new = qmp_marshal_input_stop, }, SQMP diff --git a/qmp.c b/qmp.c index 1d380b6a5..6c464792e 100644 --- a/qmp.c +++ b/qmp.c @@ -76,3 +76,8 @@ void qmp_quit(Error **err) qemu_system_shutdown_request(); } +void qmp_stop(Error **errp) +{ + vm_stop(RUN_STATE_PAUSED); +} + From 38d226535aeebda24f579446e168ae3385f4ebd6 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 15 Sep 2011 14:41:46 -0300 Subject: [PATCH 25/26] qapi: Convert system_reset Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- hmp-commands.hx | 3 +-- hmp.c | 5 +++++ hmp.h | 1 + monitor.c | 10 ---------- qapi-schema.json | 9 +++++++++ qmp-commands.hx | 5 +---- qmp.c | 4 ++++ 7 files changed, 21 insertions(+), 16 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index 3ad1ce7df..b2f5cd1f4 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -477,8 +477,7 @@ ETEXI .args_type = "", .params = "", .help = "reset the system", - .user_print = monitor_user_noop, - .mhandler.cmd_new = do_system_reset, + .mhandler.cmd = hmp_system_reset, }, STEXI diff --git a/hmp.c b/hmp.c index efcb74456..24f30bc94 100644 --- a/hmp.c +++ b/hmp.c @@ -104,3 +104,8 @@ void hmp_stop(Monitor *mon, const QDict *qdict) { qmp_stop(NULL); } + +void hmp_system_reset(Monitor *mon, const QDict *qdict) +{ + qmp_system_reset(NULL); +} diff --git a/hmp.h b/hmp.h index cb21ccea9..a49a6e674 100644 --- a/hmp.h +++ b/hmp.h @@ -25,5 +25,6 @@ void hmp_info_uuid(Monitor *mon); void hmp_info_chardev(Monitor *mon); void hmp_quit(Monitor *mon, const QDict *qdict); void hmp_stop(Monitor *mon, const QDict *qdict); +void hmp_system_reset(Monitor *mon, const QDict *qdict); #endif diff --git a/monitor.c b/monitor.c index 2a5230caa..c22687924 100644 --- a/monitor.c +++ b/monitor.c @@ -1929,16 +1929,6 @@ static void do_boot_set(Monitor *mon, const QDict *qdict) } } -/** - * do_system_reset(): Issue a machine reset - */ -static int do_system_reset(Monitor *mon, const QDict *qdict, - QObject **ret_data) -{ - qemu_system_reset_request(); - return 0; -} - /** * do_system_powerdown(): Issue a machine powerdown */ diff --git a/qapi-schema.json b/qapi-schema.json index cd0503495..02de4b55c 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -248,3 +248,12 @@ # state ## { 'command': 'stop' } + +## +# @system_reset: +# +# Performs a hard reset of a guest. +# +# Since: 0.14.0 +## +{ 'command': 'system_reset' } diff --git a/qmp-commands.hx b/qmp-commands.hx index 2ccddeed2..ea96191c1 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -223,10 +223,7 @@ EQMP { .name = "system_reset", .args_type = "", - .params = "", - .help = "reset the system", - .user_print = monitor_user_noop, - .mhandler.cmd_new = do_system_reset, + .mhandler.cmd_new = qmp_marshal_input_system_reset, }, SQMP diff --git a/qmp.c b/qmp.c index 6c464792e..51d93832a 100644 --- a/qmp.c +++ b/qmp.c @@ -81,3 +81,7 @@ void qmp_stop(Error **errp) vm_stop(RUN_STATE_PAUSED); } +void qmp_system_reset(Error **errp) +{ + qemu_system_reset_request(); +} From 5bc465e4b1b6f4582a400c0a7033a1c841744278 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 28 Sep 2011 11:06:15 -0300 Subject: [PATCH 26/26] qapi: Convert system_powerdown Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- hmp-commands.hx | 3 +-- hmp.c | 5 +++++ hmp.h | 1 + qapi-schema.json | 14 ++++++++++++++ qmp.c | 5 +++++ 5 files changed, 26 insertions(+), 2 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index b2f5cd1f4..07b493ca2 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -492,8 +492,7 @@ ETEXI .args_type = "", .params = "", .help = "send system power down event", - .user_print = monitor_user_noop, - .mhandler.cmd_new = do_system_powerdown, + .mhandler.cmd = hmp_system_powerdown, }, STEXI diff --git a/hmp.c b/hmp.c index 24f30bc94..34416fc3c 100644 --- a/hmp.c +++ b/hmp.c @@ -109,3 +109,8 @@ void hmp_system_reset(Monitor *mon, const QDict *qdict) { qmp_system_reset(NULL); } + +void hmp_system_powerdown(Monitor *mon, const QDict *qdict) +{ + qmp_system_powerdown(NULL); +} diff --git a/hmp.h b/hmp.h index a49a6e674..92433cff9 100644 --- a/hmp.h +++ b/hmp.h @@ -26,5 +26,6 @@ void hmp_info_chardev(Monitor *mon); void hmp_quit(Monitor *mon, const QDict *qdict); void hmp_stop(Monitor *mon, const QDict *qdict); void hmp_system_reset(Monitor *mon, const QDict *qdict); +void hmp_system_powerdown(Monitor *mon, const QDict *qdict); #endif diff --git a/qapi-schema.json b/qapi-schema.json index 02de4b55c..5922c4a92 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -257,3 +257,17 @@ # Since: 0.14.0 ## { 'command': 'system_reset' } + +## +# @system_powerdown: +# +# Requests that a guest perform a powerdown operation. +# +# Since: 0.14.0 +# +# Notes: A guest may or may not respond to this command. This command +# returning does not indicate that a guest has accepted the request or +# that it has shut down. Many guests will respond to this command by +# prompting the user in some way. +## +{ 'command': 'system_powerdown' } diff --git a/qmp.c b/qmp.c index 51d93832a..bf58b05a9 100644 --- a/qmp.c +++ b/qmp.c @@ -85,3 +85,8 @@ void qmp_system_reset(Error **errp) { qemu_system_reset_request(); } + +void qmp_system_powerdown(Error **erp) +{ + qemu_system_powerdown_request(); +}