[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 20/22] qapi: add code generator for libqmp
From: |
Anthony Liguori |
Subject: |
[Qemu-devel] [PATCH 20/22] qapi: add code generator for libqmp |
Date: |
Sun, 6 Mar 2011 19:23:02 -0600 |
Signed-off-by: Anthony Liguori <address@hidden>
diff --git a/Makefile b/Makefile
index 47a755d..5170675 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@ GENERATED_HEADERS = config-host.h trace.h qemu-options.def
ifeq ($(TRACE_BACKEND),dtrace)
GENERATED_HEADERS += trace-dtrace.h
endif
-GENERATED_HEADERS += qmp-types.h qmp-marshal-types.h qmp.h
+GENERATED_HEADERS += qmp-types.h qmp-marshal-types.h qmp.h libqmp.h
ifneq ($(wildcard config-host.mak),)
# Put the all: rule here so that config-host.mak can contain dependencies.
@@ -165,9 +165,16 @@ qmp.h: $(SRC_PATH)/qmp-schema.json $(SRC_PATH)/qmp-gen.py
qmp-marshal.c: $(SRC_PATH)/qmp-schema.json $(SRC_PATH)/qmp-gen.py
$(call quiet-command,python $(SRC_PATH)/qmp-gen.py --body < $< > $@, "
GEN $@")
+libqmp.h: $(SRC_PATH)/qmp-schema.json $(SRC_PATH)/qmp-gen.py
+ $(call quiet-command,python $(SRC_PATH)/qmp-gen.py --lib-header < $< >
$@, " GEN $@")
+
+libqmp.c: $(SRC_PATH)/qmp-schema.json $(SRC_PATH)/qmp-gen.py
+ $(call quiet-command,python $(SRC_PATH)/qmp-gen.py --lib-body < $< >
$@, " GEN $@")
+
qmp-types.o: qmp-types.c qmp-types.h
qmp-marshal-types.o: qmp-marshal-types.c qmp-marshal-types.h qmp-types.h
qmp-marshal.o: qmp-marshal.c qmp.h qmp-types.h qmp-marshal-types.h
+libqmp.o: libqmp.c libqmp.h qmp-types.h
version.o: $(SRC_PATH)/version.rc config-host.mak
$(call quiet-command,$(WINDRES) -I. -o $@ $<," RC $(TARGET_DIR)$@")
diff --git a/libqmp-core.c b/libqmp-core.c
new file mode 100644
index 0000000..4613d4f
--- /dev/null
+++ b/libqmp-core.c
@@ -0,0 +1,361 @@
+/*
+ * QAPI
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2. See
+ * the COPYING.LIB file in the top-level directory.
+ */
+#include "libqmp.h"
+#include "libqmp-internal.h"
+#include "libqmp-core.h"
+#include "json-streamer.h"
+#include "json-parser.h"
+#include "dirent.h"
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <assert.h>
+
+#ifndef container_of
+#define offset_of(type, field) \
+ ((unsigned long)(&((type *)0)->field))
+#define container_of(obj, type, field) \
+ ((type *)(((char *)obj) - offsetof(type, field)))
+#endif
+
+//#define DEBUG_LIBQMP 1
+
+typedef struct FdQmpSession
+{
+ QmpSession session;
+ JSONMessageParser parser;
+ QObject *result;
+ bool got_greeting;
+ int fd;
+ int event_count;
+} FdQmpSession;
+
+static EventTrampolineFunc *get_event_trampoline(QmpSession *sess, const char
*name)
+{
+ QmpEventTrampoline *t;
+
+ QTAILQ_FOREACH(t, &sess->events, node) {
+ if (strcmp(t->name, name) == 0) {
+ return t->dispatch;
+ }
+ }
+
+ return NULL;
+}
+
+static void fd_qmp_session_process_event(FdQmpSession *fs, QDict *response)
+{
+ EventTrampolineFunc *tramp;
+ QmpSignal *signal;
+ const char *event;
+ int tag;
+
+ event = qdict_get_str(response, "event");
+ tramp = get_event_trampoline(&fs->session, event);
+
+ fs->event_count++;
+
+ if (tramp && qdict_haskey(response, "tag")) {
+ tag = qdict_get_int(response, "tag");
+
+ QTAILQ_FOREACH(signal, &fs->session.signals, node) {
+ if (signal->global_handle == tag) {
+ QmpConnection *conn;
+ QDict *args = NULL;
+ Error *err = NULL;
+
+ if (qdict_haskey(response, "data")) {
+ args = qobject_to_qdict(qdict_get(response, "data"));
+ }
+
+ QTAILQ_FOREACH(conn, &signal->connections, node) {
+ tramp(args, conn->fn, conn->opaque, &err);
+ if (err) {
+ error_free(err);
+ }
+ }
+
+ break;
+ }
+ }
+ }
+}
+
+static void fd_qmp_session_parse(JSONMessageParser *parser, QList *tokens)
+{
+ FdQmpSession *fs = container_of(parser, FdQmpSession, parser);
+ QObject *result;
+
+ result = json_parser_parse(tokens, NULL);
+ if (!fs->got_greeting) {
+ fs->got_greeting = true;
+ qobject_decref(result);
+ } else {
+ QDict *response = qobject_to_qdict(result);
+ if (qdict_haskey(response, "event")) {
+ fd_qmp_session_process_event(fs, response);
+ qobject_decref(result);
+ } else {
+ qobject_decref(fs->result);
+ fs->result = result;
+ }
+ }
+}
+
+static QDict *fd_qmp_session_read(FdQmpSession *fs)
+{
+ QDict *response;
+
+ assert(fs->result == NULL);
+ fs->result = NULL;
+ while (!fs->result) {
+ char buffer[1024];
+ ssize_t len;
+
+ len = read(fs->fd, buffer, sizeof(buffer));
+ if (len == -1 && errno == EINTR) {
+ continue;
+ }
+ if (len < 1) {
+ abort();
+ }
+
+#if defined(DEBUG_LIBQMP)
+ fwrite(buffer, len, 1, stdout);
+ fflush(stdout);
+#endif
+ json_message_parser_feed(&fs->parser, buffer, len);
+ }
+
+ response = qobject_to_qdict(fs->result);
+ fs->result = NULL;
+
+ return response;
+}
+
+static bool qmp_session_fd_wait_event(QmpSession *s, struct timeval *tv)
+{
+ FdQmpSession *fs = (FdQmpSession *)s;
+ fd_set readfds;
+ int ret;
+
+ FD_ZERO(&readfds);
+ FD_SET(fs->fd, &readfds);
+
+ do {
+ ret = select(fs->fd + 1, &readfds, NULL, NULL, tv);
+ } while (ret == -1 && errno == EINTR);
+
+ if (ret) {
+ char buffer[1024];
+ ssize_t len;
+ int saved_event_count;
+
+ do {
+ len = read(fs->fd, buffer, sizeof(buffer));
+ } while (len == -1 && errno == EINTR);
+
+ if (len < 1) {
+ abort();
+ }
+
+#if defined(DEBUG_LIBQMP)
+ fwrite(buffer, len, 1, stdout);
+ fflush(stdout);
+#endif
+ saved_event_count = fs->event_count;
+ json_message_parser_feed(&fs->parser, buffer, len);
+ return (saved_event_count != fs->event_count);
+ }
+
+ return false;
+}
+
+static QObject *qmp_session_fd_dispatch(QmpSession *s, const char *name,
+ QDict *args, Error **err)
+{
+ FdQmpSession *fs = (FdQmpSession *)s;
+ QString *str;
+ const char *buffer;
+ size_t size;
+ size_t offset;
+ QDict *request = qdict_new();
+ QDict *response;
+
+ qdict_put(request, "execute", qstring_from_str(name));
+
+ if (qdict_size(args)) {
+ QINCREF(args);
+ qdict_put(request, "arguments", args);
+ }
+
+ str = qobject_to_json(QOBJECT(request));
+ buffer = qstring_get_str(str);
+ size = str->length;
+
+ offset = 0;
+ while (offset < size) {
+ ssize_t len;
+
+ len = write(fs->fd, buffer + offset, size - offset);
+ if (len == -1 && errno == EINTR) {
+ continue;
+ }
+ if (len < 1) {
+ abort();
+ }
+
+#if defined(DEBUG_LIBQMP)
+ fwrite(buffer + offset, size - offset, 1, stdout);
+ fflush(stdout);
+#endif
+ offset += len;
+ }
+
+ QDECREF(str);
+ QDECREF(request);
+
+ response = fd_qmp_session_read(fs);
+
+ if (qdict_haskey(response, "error")) {
+ error_set_qobject(err, qdict_get(response, "error"));
+ QDECREF(response);
+ return NULL;
+ } else {
+ QObject *result = qdict_get(response, "return");
+ qobject_incref(result);
+ QDECREF(response);
+ return result;
+ }
+}
+
+void libqmp_register_event(QmpSession *sess, const char *name,
EventTrampolineFunc *func)
+{
+ QmpEventTrampoline *t = qemu_mallocz(sizeof(*t));
+ t->name = name;
+ t->dispatch = func;
+ QTAILQ_INSERT_TAIL(&sess->events, t, node);
+}
+
+QmpSession *qmp_session_new(int fd)
+{
+ FdQmpSession *s = qemu_mallocz(sizeof(*s));
+
+ s->fd = fd;
+ s->session.dispatch = qmp_session_fd_dispatch;
+ s->session.wait_event = qmp_session_fd_wait_event;
+ s->got_greeting = false;
+
+ QTAILQ_INIT(&s->session.events);
+ QTAILQ_INIT(&s->session.signals);
+ json_message_parser_init(&s->parser, fd_qmp_session_parse);
+
+ libqmp_init_events(&s->session);
+ libqmp_qmp_capabilities(&s->session, NULL);
+
+ return &s->session;
+}
+
+void qmp_session_destroy(QmpSession *s)
+{
+ FdQmpSession *fs = container_of(s, FdQmpSession, session);
+
+ while (!QTAILQ_EMPTY(&s->events)) {
+ QmpEventTrampoline *t = QTAILQ_FIRST(&s->events);
+ QTAILQ_REMOVE(&s->events, t, node);
+ qemu_free(t);
+ }
+ if (fs->result) {
+ qobject_decref(fs->result);
+ fs->result = NULL;
+ }
+ json_message_parser_destroy(&fs->parser);
+ close(fs->fd);
+ qemu_free(fs);
+}
+
+typedef struct GenericSignal
+{
+ QmpSignal *signal;
+} GenericSignal;
+
+void *libqmp_signal_new(QmpSession *s, size_t size, int global_handle)
+{
+ GenericSignal *obj;
+ obj = qemu_mallocz(size);
+ obj->signal = qemu_mallocz(sizeof(QmpSignal));
+ obj->signal->sess = s;
+ obj->signal->global_handle = global_handle;
+ // FIXME validate there isn't another global_handle
+ QTAILQ_INIT(&obj->signal->connections);
+ QTAILQ_INSERT_TAIL(&s->signals, obj->signal, node);
+ return obj;
+}
+
+int libqmp_signal_connect(QmpSignal *obj, void *func, void *opaque)
+{
+ QmpConnection *conn;
+
+ conn = qemu_mallocz(sizeof(*conn));
+ conn->fn = func;
+ conn->opaque = opaque;
+ conn->handle = ++obj->max_handle;
+ QTAILQ_INSERT_TAIL(&obj->connections, conn, node);
+ return conn->handle;
+}
+
+void libqmp_signal_disconnect(QmpSignal *obj, int handle)
+{
+ QmpConnection *conn;
+
+ QTAILQ_FOREACH(conn, &obj->connections, node) {
+ if (conn->handle == handle) {
+ break;
+ }
+ }
+ if (conn) {
+ QTAILQ_REMOVE(&obj->connections, conn, node);
+ qemu_free(conn);
+ }
+}
+
+void libqmp_signal_free(void *base, QmpSignal *obj)
+{
+ QTAILQ_REMOVE(&obj->sess->signals, obj, node);
+
+ libqmp_put_event(obj->sess, obj->global_handle, NULL);
+ while (!QTAILQ_EMPTY(&obj->connections)) {
+ QmpConnection *conn = QTAILQ_FIRST(&obj->connections);
+ QTAILQ_REMOVE(&obj->connections, conn, node);
+ qemu_free(conn);
+ }
+ qemu_free(obj);
+ qemu_free(base);
+}
+
+bool libqmp_wait_event(QmpSession *s, struct timeval *tv)
+{
+ return s->wait_event(s, tv);
+}
+
+bool libqmp_poll_event(QmpSession *s)
+{
+ struct timeval tv = { 0, 0 };
+ bool got_event = false;
+ bool ret;
+
+ do {
+ ret = libqmp_wait_event(s, &tv);
+ got_event |= ret;
+ } while (ret);
+
+ return got_event;
+}
diff --git a/libqmp-core.h b/libqmp-core.h
new file mode 100644
index 0000000..c1063e6
--- /dev/null
+++ b/libqmp-core.h
@@ -0,0 +1,44 @@
+/*
+ * QAPI
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2. See
+ * the COPYING.LIB file in the top-level directory.
+ */
+#ifndef LIBQMP_CORE_H
+#define LIBQMP_CORE_H
+
+#include <sys/types.h>
+#include "qmp-types.h"
+#include "error.h"
+
+typedef struct QmpSession QmpSession;
+
+QmpSession *qmp_session_new(int fd);
+void qmp_session_destroy(QmpSession *s);
+
+bool libqmp_poll_event(QmpSession *s);
+bool libqmp_wait_event(QmpSession *s, struct timeval *tv);
+
+void *libqmp_signal_new(QmpSession *s, size_t size, int global_handle);
+int libqmp_signal_connect(QmpSignal *obj, void *func, void *opaque);
+void libqmp_signal_disconnect(QmpSignal *obj, int handle);
+void libqmp_signal_free(void *base, QmpSignal *obj);
+
+#define libqmp_signal_init(s, type, global_handle) \
+ ((type *)libqmp_signal_new(s, sizeof(type), global_handle))
+
+#define signal_connect(obj, fn, opaque) \
+ libqmp_signal_connect((obj)->signal, (obj)->func = fn, opaque)
+
+#define signal_disconnect(obj, handle) \
+ libqmp_signal_disconnect((obj)->signal, handle)
+
+#define signal_unref(obj) \
+ libqmp_signal_free((obj), (obj)->signal)
+
+#endif
diff --git a/libqmp-internal.h b/libqmp-internal.h
new file mode 100644
index 0000000..01a3dd8
--- /dev/null
+++ b/libqmp-internal.h
@@ -0,0 +1,56 @@
+/*
+ * QAPI
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2. See
+ * the COPYING.LIB file in the top-level directory.
+ */
+#ifndef LIBQMP_INTERNAL_H
+#define LIBQMP_INTERNAL_H
+
+#include "qemu-objects.h"
+#include "qmp-marshal-types.h"
+#include "error_int.h"
+
+typedef void (EventTrampolineFunc)(QDict *qmp__args, void *qmp__fn, void
*qmp__opaque, Error **qmp__errp);
+
+typedef struct QmpEventTrampoline
+{
+ const char *name;
+ EventTrampolineFunc *dispatch;
+ QTAILQ_ENTRY(QmpEventTrampoline) node;
+} QmpEventTrampoline;
+
+typedef struct QmpConnection
+{
+ void *fn;
+ void *opaque;
+ int handle;
+ QTAILQ_ENTRY(QmpConnection) node;
+} QmpConnection;
+
+struct QmpSignal
+{
+ QmpSession *sess;
+ int global_handle;
+ int max_handle;
+ QTAILQ_HEAD(, QmpConnection) connections;
+ QTAILQ_ENTRY(QmpSignal) node;
+};
+
+struct QmpSession
+{
+ QObject *(*dispatch)(QmpSession *session, const char *name, QDict *args,
Error **err);
+ bool (*wait_event)(QmpSession *session, struct timeval *tv);
+ QTAILQ_HEAD(, QmpEventTrampoline) events;
+ QTAILQ_HEAD(, QmpSignal) signals;
+};
+
+void libqmp_init_events(QmpSession *sess);
+void libqmp_register_event(QmpSession *sess, const char *name,
EventTrampolineFunc *func);
+
+#endif
diff --git a/qmp-gen.py b/qmp-gen.py
index aac0f90..401b85a 100644
--- a/qmp-gen.py
+++ b/qmp-gen.py
@@ -650,6 +650,171 @@ static void qmp_marshal_%s(const QDict *qdict, QObject
**ret_data, Error **err)
print '}'
+
+def print_lib_decl(name, required, optional, retval, suffix=''):
+ args = ['QmpSession *qmp__session']
+ for key in required:
+ args.append('%s %s' % (qmp_type_to_c(required[key]), c_var(key)))
+
+ for key in optional:
+ if optional[key] == '**':
+ args.append('KeyValues * %s' % c_var(key))
+ else:
+ args.append('bool has_%s' % c_var(key))
+ args.append('%s %s' % (qmp_type_to_c(optional[key]), c_var(key)))
+
+ args.append('Error **qmp__err')
+
+ print '%s libqmp_%s(%s)%s' % (qmp_type_to_c(retval, True), c_var(name), ',
'.join(args), suffix)
+
+def print_lib_event_decl(name, end=''):
+ print 'static void libqmp_notify_%s(QDict *qmp__args, void *qmp__fn, void
*qmp__opaque, Error **qmp__errp)%s' % (de_camel_case(qmp_event_to_c(name)), end)
+
+def print_lib_declaration(name, required, optional, retval):
+ print_lib_decl(name, required, optional, retval, ';')
+
+def print_lib_event_definition(name, typeinfo):
+ print
+ print_lib_event_decl(name)
+ print '{'
+ print ' %s *qmp__native_fn = qmp__fn;' % (qmp_event_func_to_c(name))
+ print ' Error *qmp__err = NULL;'
+ for argname, argtype, optional in parse_args(typeinfo):
+ if optional:
+ print ' bool has_%s;' % (c_var(argname))
+ print ' %s %s = 0;' % (qmp_type_to_c(argtype, True), c_var(argname))
+
+ print
+ print ' (void)qmp__err;'
+
+ for argname, argtype, optional in parse_args(typeinfo):
+ if optional:
+ print ' BUILD_BUG()'
+ print '''
+ if (!qdict_haskey(qmp__args, "%s")) {
+ error_set(qmp__errp, QERR_MISSING_PARAMETER, "%s");
+ goto qmp__out;
+ }
+
+ %s = %s(qdict_get(qmp__args, "%s"), &qmp__err);
+ if (qmp__err) {
+ if (error_is_type(qmp__err, QERR_INVALID_PARAMETER_TYPE)) {
+ error_set(qmp__errp, QERR_INVALID_PARAMETER_TYPE, "%s",
+ error_get_field(qmp__err, "expected"));
+ error_free(qmp__err);
+ qmp__err = NULL;
+ } else {
+ error_propagate(qmp__errp, qmp__err);
+ }
+ goto qmp__out;
+ }''' % (argname, argname, c_var(argname), qmp_type_from_qobj(argtype),
argname, argname)
+
+ arglist = ['qmp__opaque']
+ for argname, argtype, optional in parse_args(typeinfo):
+ arglist.append(c_var(argname))
+ print
+ print ' qmp__native_fn(%s);' % (', '.join(arglist))
+
+ has_label = False
+ for argname, argtype, optional in parse_args(typeinfo):
+ if not has_label:
+ print
+ print 'qmp__out:'
+ has_label = True
+
+ if qmp_type_should_free(argtype):
+ print ' %s(%s);' % (qmp_free_func(argtype), c_var(argname))
+ print ' return;'
+ print '}'
+
+def print_lib_definition(name, required, optional, retval):
+ print
+ print_lib_decl(name, required, optional, retval)
+ print '''{
+ QDict *qmp__args = qdict_new();
+ Error *qmp__local_err = NULL;'''
+
+ print ' QObject *qmp__retval = NULL;'
+ if retval != 'none':
+ print ' %s qmp__native_retval = 0;' % (qmp_type_to_c(retval, True))
+ if qmp_type_is_event(retval):
+ print ' int qmp__global_handle = 0;'
+ print
+
+ for key in required:
+ argname = key
+ argtype = required[key]
+ print ' qdict_put_obj(qmp__args, "%s", %s(%s));' % (key,
qmp_type_to_qobj_ctor(argtype), c_var(argname))
+ if required:
+ print
+
+ for key in optional:
+ argname = key
+ argtype = optional[key]
+ if argtype.startswith('**'):
+ print ''' {
+ KeyValues *qmp__i;
+ for (qmp__i = %s; qmp__i; qmp__i = qmp__i->next) {
+ qdict_put(qmp__args, qmp__i->key, qstring_from_str(qmp__i->value));
+ }
+ }''' % c_var(argname)
+ continue
+ print ' if (has_%s) {' % c_var(argname)
+ print ' qdict_put_obj(qmp__args, "%s", %s(%s));' % (key,
qmp_type_to_qobj_ctor(argtype), c_var(argname))
+ print ' }'
+ print
+
+ print ' qmp__retval = qmp__session->dispatch(qmp__session, "%s",
qmp__args, &qmp__local_err);' % name
+
+ print
+ print ' QDECREF(qmp__args);'
+
+ if type(retval) == list:
+ print '''
+ if (!qmp__local_err) {
+ QList *qmp__list_retval = qobject_to_qlist(qmp__retval);
+ QListEntry *qmp__i;
+ QLIST_FOREACH_ENTRY(qmp__list_retval, qmp__i) {
+ %s qmp__native_i = %s(qmp__i->value, &qmp__local_err);
+ if (qmp__local_err) {
+ %s(qmp__native_retval);
+ break;
+ }
+ qmp__native_i->next = qmp__native_retval;
+ qmp__native_retval = qmp__native_i;
+ }
+ qobject_decref(qmp__retval);
+ }
+ error_propagate(qmp__err, qmp__local_err);
+ return qmp__native_retval;''' % (qmp_type_to_c(retval[0], True),
qmp_type_from_qobj(retval[0]), qmp_free_func(retval[0]))
+ elif is_dict(retval):
+ print ' // FIXME (using an anonymous dict as return value)'
+ print ' BUILD_BUG();'
+ elif qmp_type_is_event(retval):
+ print ''' if (!qmp__local_err) {
+ qmp__global_handle = %s(qmp__retval, &qmp__local_err);
+ qobject_decref(qmp__retval);
+ qmp__retval = NULL;
+ }
+ if (!qmp__local_err) {
+ qmp__native_retval = libqmp_signal_init(qmp__session, %s,
qmp__global_handle);
+ }
+ error_propagate(qmp__err, qmp__local_err);
+ return qmp__native_retval;''' % (qmp_type_from_qobj('int'),
qmp_event_to_c(retval))
+ elif retval != 'none':
+ print '''
+ if (!qmp__local_err) {
+ qmp__native_retval = %s(qmp__retval, &qmp__local_err);
+ qobject_decref(qmp__retval);
+ }
+ error_propagate(qmp__err, qmp__local_err);
+ return qmp__native_retval;''' % qmp_type_from_qobj(retval)
+ else:
+ print ' qobject_decref(qmp__retval);'
+ print ' error_propagate(qmp__err, qmp__local_err);'
+
+ print '}'
+
def tokenize(data):
while len(data):
if data[0] in ['{', '}', ':', ',', '[', ']']:
@@ -713,7 +878,10 @@ if len(sys.argv) == 2:
kind = 'body'
elif sys.argv[1] == '--header':
kind = 'header'
-
+ elif sys.argv[1] == '--lib-header':
+ kind = 'lib-header'
+ elif sys.argv[1] == '--lib-body':
+ kind = 'lib-body'
if kind == 'types-header':
print '''/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT EDIT */
@@ -759,6 +927,19 @@ elif kind == 'body':
#include "qmp.h"
#include "qmp-core.h"
'''
+elif kind == 'lib-header':
+ print '''/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT EDIT */
+#ifndef LIBQMP_H
+#define LIBQMP_H
+
+#include "libqmp-core.h"
+'''
+elif kind == 'lib-body':
+ print '''/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT EDIT */
+
+#include "libqmp.h"
+#include "libqmp-internal.h"
+'''
exprs = []
expr = ''
@@ -794,6 +975,9 @@ for s in exprs:
print_type_marshal_definition(key, s[key])
elif kind == 'marshal-header':
print_type_marshal_declaration(key, s[key])
+ elif kind == 'lib-body':
+ if qmp_type_is_event(key):
+ print_lib_event_definition(key, event_types[key])
else:
enum_types.append(key)
if kind == 'types-header':
@@ -810,6 +994,10 @@ for s in exprs:
print_definition(name, required, optional, retval)
elif kind == 'header':
print_declaration(name, required, optional, retval)
+ elif kind == 'lib-body':
+ print_lib_definition(name, required, optional, retval)
+ elif kind == 'lib-header':
+ print_lib_declaration(name, required, optional, retval)
if kind.endswith('header'):
print '#endif'
@@ -827,3 +1015,10 @@ elif kind == 'body':
print '};'
print
print 'qapi_init(qmp_init_marshal);'
+elif kind == 'lib-body':
+ print
+ print 'void libqmp_init_events(QmpSession *sess)'
+ print '{'
+ for event in event_types:
+ print ' libqmp_register_event(sess, "%s", &libqmp_notify_%s);' %
(event, de_camel_case(qmp_event_to_c(event)))
+ print '}'
--
1.7.0.4
- Re: [Qemu-devel] [PATCH 19/22] qapi: add QMP put-event command, (continued)
[Qemu-devel] [PATCH 21/22] qapi: add test-libqmp, Anthony Liguori, 2011/03/06
[Qemu-devel] [PATCH 22/22] qapi: generate HTML report for test-libqmp, Anthony Liguori, 2011/03/06
[Qemu-devel] [PATCH 01/22] Add hard build dependency on glib, Anthony Liguori, 2011/03/06
[Qemu-devel] [PATCH 20/22] qapi: add code generator for libqmp,
Anthony Liguori <=
[Qemu-devel] [PATCH 04/22] qerror: split out the reporting bits of QError, Anthony Liguori, 2011/03/06
[Qemu-devel] [PATCH 08/22] qapi: add code generator for qmp-types, Anthony Liguori, 2011/03/06
[Qemu-devel] [PATCH 09/22] qapi: add code generator for type marshallers, Anthony Liguori, 2011/03/06
[Qemu-devel] [PATCH 05/22] qerror: add new error message for invalid enum values, Anthony Liguori, 2011/03/06
[Qemu-devel] [PATCH] qapi: qmp-types.c and qmp-types.h, Anthony Liguori, 2011/03/06
[Qemu-devel] [PATCH] qapi: qmp-marshal-types.c and qmp-marshal-types.h, Anthony Liguori, 2011/03/06
[Qemu-devel] [PATCH] qapi: add qmp-marshal.c and qmp.h, Anthony Liguori, 2011/03/06
[Qemu-devel] [PATCH] qapi: add libqmp.c and libqmp.h, Anthony Liguori, 2011/03/06
Re: [Qemu-devel] [PATCH 00/22] QAPI Round 1, Stefan Hajnoczi, 2011/03/07