From patchwork Mon Mar 7 01:23:02 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anthony Liguori X-Patchwork-Id: 85631 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 2D5DEB70D1 for ; Mon, 7 Mar 2011 12:48:35 +1100 (EST) Received: from localhost ([127.0.0.1]:45043 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PwPVG-0000uI-Cu for incoming@patchwork.ozlabs.org; Sun, 06 Mar 2011 20:44:54 -0500 Received: from [140.186.70.92] (port=47651 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PwPAf-0007dT-1v for qemu-devel@nongnu.org; Sun, 06 Mar 2011 20:23:39 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PwPAY-0000RG-Nn for qemu-devel@nongnu.org; Sun, 06 Mar 2011 20:23:36 -0500 Received: from e3.ny.us.ibm.com ([32.97.182.143]:39782) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PwPAY-0000R7-Is for qemu-devel@nongnu.org; Sun, 06 Mar 2011 20:23:30 -0500 Received: from d01dlp01.pok.ibm.com (d01dlp01.pok.ibm.com [9.56.224.56]) by e3.ny.us.ibm.com (8.14.4/8.13.1) with ESMTP id p2713LvB029172 for ; Sun, 6 Mar 2011 20:03:21 -0500 Received: from d01relay06.pok.ibm.com (d01relay06.pok.ibm.com [9.56.227.116]) by d01dlp01.pok.ibm.com (Postfix) with ESMTP id 6292C38C803B for ; Sun, 6 Mar 2011 20:23:28 -0500 (EST) Received: from d01av01.pok.ibm.com (d01av01.pok.ibm.com [9.56.224.215]) by d01relay06.pok.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id p271NTfc2666688 for ; Sun, 6 Mar 2011 20:23:29 -0500 Received: from d01av01.pok.ibm.com (loopback [127.0.0.1]) by d01av01.pok.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id p271NTh8021204 for ; Sun, 6 Mar 2011 20:23:29 -0500 Received: from localhost.localdomain (sig-9-65-217-198.mts.ibm.com [9.65.217.198]) by d01av01.pok.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id p271N9Mb020370; Sun, 6 Mar 2011 20:23:28 -0500 From: Anthony Liguori To: qemu-devel@nongnu.org Date: Sun, 6 Mar 2011 19:23:02 -0600 Message-Id: <1299460984-15849-21-git-send-email-aliguori@us.ibm.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1299460984-15849-1-git-send-email-aliguori@us.ibm.com> References: <1299460984-15849-1-git-send-email-aliguori@us.ibm.com> X-Content-Scanned: Fidelis XPS MAILER X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) X-Received-From: 32.97.182.143 Cc: Adam Litke , Anthony Liguori , Markus Armbruster , Luiz Capitulino Subject: [Qemu-devel] [PATCH 20/22] qapi: add code generator for libqmp X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Signed-off-by: Anthony Liguori 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 + * + * 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 +#include +#include + +#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 + * + * 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 +#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 + * + * 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 '}'