From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from [140.186.70.92] (port=54538 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PyBPA-00046B-Hr for qemu-devel@nongnu.org; Fri, 11 Mar 2011 18:05:57 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PyBP9-0006ux-5i for qemu-devel@nongnu.org; Fri, 11 Mar 2011 18:05:56 -0500 Received: from e5.ny.us.ibm.com ([32.97.182.145]:48539) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PyBP9-0006up-09 for qemu-devel@nongnu.org; Fri, 11 Mar 2011 18:05:55 -0500 Received: from d01dlp02.pok.ibm.com (d01dlp02.pok.ibm.com [9.56.224.85]) by e5.ny.us.ibm.com (8.14.4/8.13.1) with ESMTP id p2BMewAg010255 for ; Fri, 11 Mar 2011 17:40:58 -0500 Received: from d01relay01.pok.ibm.com (d01relay01.pok.ibm.com [9.56.227.233]) by d01dlp02.pok.ibm.com (Postfix) with ESMTP id 9C6AC6E8036 for ; Fri, 11 Mar 2011 18:05:54 -0500 (EST) Received: from d01av04.pok.ibm.com (d01av04.pok.ibm.com [9.56.224.64]) by d01relay01.pok.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id p2BN5sQn391864 for ; Fri, 11 Mar 2011 18:05:54 -0500 Received: from d01av04.pok.ibm.com (loopback [127.0.0.1]) by d01av04.pok.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id p2BN5slk027300 for ; Fri, 11 Mar 2011 18:05:54 -0500 From: Anthony Liguori Date: Fri, 11 Mar 2011 17:05:34 -0600 Message-Id: <1299884745-521-5-git-send-email-aliguori@us.ibm.com> In-Reply-To: <1299884745-521-1-git-send-email-aliguori@us.ibm.com> References: <1299884745-521-1-git-send-email-aliguori@us.ibm.com> Subject: [Qemu-devel] [PATCH 04/15] qapi: add signal support to core QMP server List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Adam Litke , Anthony Liguori , Luiz Capitulino , Avi Kivity , Markus Armbruster Signed-off-by: Anthony Liguori diff --git a/qmp-core.c b/qmp-core.c index d906557..7f60942 100644 --- a/qmp-core.c +++ b/qmp-core.c @@ -42,6 +42,13 @@ struct QmpCommandState QObject *tag; }; +struct QmpState +{ + int (*add_connection)(QmpState *s, QmpConnection *conn); + void (*del_connection)(QmpState *s, int global_handle, Error **errp); + void (*event)(QmpState *s, QObject *data); +}; + static QTAILQ_HEAD(, QmpCommand) qmp_commands = QTAILQ_HEAD_INITIALIZER(qmp_commands); @@ -111,3 +118,90 @@ char *qobject_as_string(QObject *obj) return NULL; } } + +void qmp_state_add_connection(QmpState *sess, const char *event_name, QmpSignal *obj, int handle, QmpConnection *conn) +{ + conn->state = sess; + conn->event_name = event_name; + conn->signal = obj; + conn->handle = handle; + conn->global_handle = sess->add_connection(sess, conn); +} + +void qmp_put_event(QmpState *sess, int global_handle, Error **errp) +{ + sess->del_connection(sess, global_handle, errp); +} + +void qmp_state_event(QmpConnection *conn, QObject *data) +{ + QDict *event = qdict_new(); + qemu_timeval tv; + QObject *ts; + + qemu_gettimeofday(&tv); + + ts = qobject_from_jsonf("{ 'seconds': %" PRId64 ", " + "'microseconds': %" PRId64 " }", + (int64_t)tv.tv_sec, (int64_t)tv.tv_usec); + qdict_put_obj(event, "timestamp", ts); + + qdict_put(event, "event", qstring_from_str(conn->event_name)); + if (data) { + qobject_incref(data); + qdict_put_obj(event, "data", data); + } + + qdict_put(event, "tag", qint_from_int(conn->global_handle)); + + conn->state->event(conn->state, QOBJECT(event)); + QDECREF(event); +} + +QmpSignal *qmp_signal_init(void) +{ + QmpSignal *obj = qemu_mallocz(sizeof(*obj)); + obj->max_handle = 0; + obj->ref = 1; + QTAILQ_INIT(&obj->slots); + return obj; +} + +void qmp_signal_ref(QmpSignal *obj) +{ + obj->ref++; +} + +void qmp_signal_unref(QmpSignal *obj) +{ + if (--obj->ref) { + qemu_free(obj); + } +} + +int qmp_signal_connect(QmpSignal *obj, void *func, void *opaque) +{ + int handle = ++obj->max_handle; + QmpSlot *slot = qemu_mallocz(sizeof(*slot)); + + slot->handle = handle; + slot->func = func; + slot->opaque = opaque; + + QTAILQ_INSERT_TAIL(&obj->slots, slot, node); + + return handle; +} + +void qmp_signal_disconnect(QmpSignal *obj, int handle) +{ + QmpSlot *slot; + + QTAILQ_FOREACH(slot, &obj->slots, node) { + if (slot->handle == handle) { + QTAILQ_REMOVE(&obj->slots, slot, node); + qemu_free(slot); + break; + } + } +} diff --git a/qmp-core.h b/qmp-core.h index 4765b69..c9c8b63 100644 --- a/qmp-core.h +++ b/qmp-core.h @@ -20,6 +20,31 @@ typedef void (QmpCommandFunc)(const QDict *, QObject **, Error **); typedef void (QmpStatefulCommandFunc)(QmpState *qmp__sess, const QDict *, QObject **, Error **); typedef void (QmpAsyncCommandFunc)(const QDict *, Error **, QmpCommandState *); +typedef struct QmpSlot +{ + int handle; + void *func; + void *opaque; + QTAILQ_ENTRY(QmpSlot) node; +} QmpSlot; + +struct QmpSignal +{ + int max_handle; + int ref; + QTAILQ_HEAD(, QmpSlot) slots; +}; + +typedef struct QmpConnection +{ + QmpState *state; + const char *event_name; + QmpSignal *signal; + int handle; + int global_handle; + QTAILQ_ENTRY(QmpConnection) node; +} QmpConnection; + void qmp_register_command(const char *name, QmpCommandFunc *fn); void qmp_register_stateful_command(const char *name, QmpStatefulCommandFunc *fn); void qmp_register_async_command(const char *name, QmpAsyncCommandFunc *fn); @@ -28,4 +53,34 @@ void qmp_async_complete_command(QmpCommandState *cmd, QObject *retval, Error *er char *qobject_as_string(QObject *obj); +QmpSignal *qmp_signal_init(void); +void qmp_signal_ref(QmpSignal *obj); +void qmp_signal_unref(QmpSignal *obj); +int qmp_signal_connect(QmpSignal *obj, void *func, void *opaque); +void qmp_signal_disconnect(QmpSignal *obj, int handle); + +void qmp_state_add_connection(QmpState *sess, const char *name, QmpSignal *obj, int handle, QmpConnection *conn); +void qmp_put_event(QmpState *sess, int global_handle, Error **errp); +void qmp_state_event(QmpConnection *conn, QObject *data); + +#define signal_init(obj) do { \ + (obj)->signal = qmp_signal_init(); \ +} while (0) + +#define signal_unref(obj) qmp_signal_unref((obj)->signal) + +#define signal_connect(obj, fn, opaque) \ + qmp_signal_connect((obj)->signal, (obj)->func = fn, opaque) + +#define signal_disconnect(obj, handle) \ + qmp_signal_disconnect((obj)->signal, handle) + +#define signal_notify(obj, ...) do { \ + QmpSlot *qmp__slot; \ + QTAILQ_FOREACH(qmp__slot, &(obj)->signal->slots, node) { \ + (obj)->func = qmp__slot->func; \ + (obj)->func(qmp__slot->opaque, ## __VA_ARGS__); \ + } \ +} while(0) + #endif -- 1.7.0.4