qemu-e2k/qapi/qapi-dealloc-visitor.c

206 lines
5.0 KiB
C
Raw Normal View History

/*
* Dealloc Visitor
*
* Copyright (C) 2012-2016 Red Hat, Inc.
* Copyright IBM, Corp. 2011
*
* Authors:
* Michael Roth <mdroth@linux.vnet.ibm.com>
*
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
* See the COPYING.LIB file in the top-level directory.
*
*/
#include "qemu/osdep.h"
#include "qapi/dealloc-visitor.h"
#include "qemu/queue.h"
#include "qemu-common.h"
#include "qapi/qmp/types.h"
#include "qapi/visitor-impl.h"
typedef struct StackEntry
{
void *value;
bool is_list_head;
QTAILQ_ENTRY(StackEntry) node;
} StackEntry;
struct QapiDeallocVisitor
{
Visitor visitor;
QTAILQ_HEAD(, StackEntry) stack;
};
static QapiDeallocVisitor *to_qov(Visitor *v)
{
return container_of(v, QapiDeallocVisitor, visitor);
}
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);
}
static void *qapi_dealloc_pop(QapiDeallocVisitor *qov)
{
StackEntry *e = QTAILQ_FIRST(&qov->stack);
QObject *value;
QTAILQ_REMOVE(&qov->stack, e, node);
value = e->value;
g_free(e);
return value;
}
static void qapi_dealloc_start_struct(Visitor *v, const char *name, void **obj,
size_t unused, Error **errp)
{
QapiDeallocVisitor *qov = to_qov(v);
qapi_dealloc_push(qov, obj);
}
qapi: Split visit_end_struct() into pieces As mentioned in previous patches, we want to call visit_end_struct() functions unconditionally, so that visitors can release resources tied up since the matching visit_start_struct() without also having to worry about error priority if more than one error occurs. Even though error_propagate() can be safely used to ignore a second error during cleanup caused by a first error, it is simpler if the cleanup cannot set an error. So, split out the error checking portion (basically, input visitors checking for unvisited keys) into a new function visit_check_struct(), which can be safely skipped if any earlier errors are encountered, and leave the cleanup portion (which never fails, but must be called unconditionally if visit_start_struct() succeeded) in visit_end_struct(). Generated code in qapi-visit.c has diffs resembling: |@@ -59,10 +59,12 @@ void visit_type_ACPIOSTInfo(Visitor *v, | goto out_obj; | } | visit_type_ACPIOSTInfo_members(v, obj, &err); |- error_propagate(errp, err); |- err = NULL; |+ if (err) { |+ goto out_obj; |+ } |+ visit_check_struct(v, &err); | out_obj: |- visit_end_struct(v, &err); |+ visit_end_struct(v); | out: and in qapi-event.c: @@ -47,7 +47,10 @@ void qapi_event_send_acpi_device_ost(ACP | goto out; | } | visit_type_q_obj_ACPI_DEVICE_OST_arg_members(v, &param, &err); |- visit_end_struct(v, err ? NULL : &err); |+ if (!err) { |+ visit_check_struct(v, &err); |+ } |+ visit_end_struct(v); | if (err) { | goto out; Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1461879932-9020-20-git-send-email-eblake@redhat.com> [Conflict with a doc fixup resolved] Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-04-28 23:45:27 +02:00
static void qapi_dealloc_end_struct(Visitor *v)
{
QapiDeallocVisitor *qov = to_qov(v);
void **obj = qapi_dealloc_pop(qov);
if (obj) {
g_free(*obj);
}
}
static void qapi_dealloc_start_alternate(Visitor *v, const char *name,
GenericAlternate **obj, size_t size,
bool promote_int, Error **errp)
{
QapiDeallocVisitor *qov = to_qov(v);
qapi_dealloc_push(qov, obj);
}
static void qapi_dealloc_end_alternate(Visitor *v)
{
QapiDeallocVisitor *qov = to_qov(v);
void **obj = qapi_dealloc_pop(qov);
if (obj) {
g_free(*obj);
}
}
static void qapi_dealloc_start_list(Visitor *v, const char *name, Error **errp)
{
QapiDeallocVisitor *qov = to_qov(v);
qapi_dealloc_push(qov, NULL);
}
qapi: Adjust layout of FooList types By sticking the next pointer first, we don't need a union with 64-bit padding for smaller types. On 32-bit platforms, this can reduce the size of uint8List from 16 bytes (or 12, depending on whether 64-bit ints can tolerate 4-byte alignment) down to 8. It has no effect on 64-bit platforms (where alignment still dictates a 16-byte struct); but fewer anonymous unions is still a win in my book. It requires visit_next_list() to gain a size parameter, to know what size element to allocate; comparable to the size parameter of visit_start_struct(). I debated about going one step further, to allow for fewer casts, by doing: typedef GenericList GenericList; struct GenericList { GenericList *next; }; struct FooList { GenericList base; Foo *value; }; so that you convert to 'GenericList *' by '&foolist->base', and back by 'container_of(generic, GenericList, base)' (as opposed to the existing '(GenericList *)foolist' and '(FooList *)generic'). But doing that would require hoisting the declaration of GenericList prior to inclusion of qapi-types.h, rather than its current spot in visitor.h; it also makes iteration a bit more verbose through 'foolist->base.next' instead of 'foolist->next'. Note that for lists of objects, the 'value' payload is still hidden behind a boxed pointer. Someday, it would be nice to do: struct FooList { FooList *next; Foo value; }; for one less level of malloc for each list element. This patch is a step in that direction (now that 'next' is no longer at a fixed non-zero offset within the struct, we can store more than just a pointer's-worth of data as the value payload), but the actual conversion would be a task for another series, as it will touch a lot of code. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1455778109-6278-10-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-02-18 07:48:23 +01:00
static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList **listp,
size_t size)
{
GenericList *list = *listp;
QapiDeallocVisitor *qov = to_qov(v);
StackEntry *e = QTAILQ_FIRST(&qov->stack);
if (e && e->is_list_head) {
e->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)
{
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, const char *name, char **obj,
Error **errp)
{
if (obj) {
g_free(*obj);
}
}
static void qapi_dealloc_type_int64(Visitor *v, const char *name, int64_t *obj,
Error **errp)
{
}
static void qapi_dealloc_type_uint64(Visitor *v, const char *name,
uint64_t *obj, Error **errp)
{
}
static void qapi_dealloc_type_bool(Visitor *v, const char *name, bool *obj,
Error **errp)
{
}
static void qapi_dealloc_type_number(Visitor *v, const char *name, double *obj,
Error **errp)
{
}
static void qapi_dealloc_type_anything(Visitor *v, const char *name,
QObject **obj, Error **errp)
{
if (obj) {
qobject_decref(*obj);
}
}
2016-04-28 23:45:22 +02:00
static void qapi_dealloc_type_null(Visitor *v, const char *name, Error **errp)
{
}
Visitor *qapi_dealloc_get_visitor(QapiDeallocVisitor *v)
{
return &v->visitor;
}
void qapi_dealloc_visitor_cleanup(QapiDeallocVisitor *v)
{
g_free(v);
}
QapiDeallocVisitor *qapi_dealloc_visitor_new(void)
{
QapiDeallocVisitor *v;
v = g_malloc0(sizeof(*v));
v->visitor.type = VISITOR_DEALLOC;
v->visitor.start_struct = qapi_dealloc_start_struct;
v->visitor.end_struct = qapi_dealloc_end_struct;
v->visitor.start_alternate = qapi_dealloc_start_alternate;
v->visitor.end_alternate = qapi_dealloc_end_alternate;
v->visitor.start_list = qapi_dealloc_start_list;
v->visitor.next_list = qapi_dealloc_next_list;
v->visitor.end_list = qapi_dealloc_end_list;
v->visitor.type_int64 = qapi_dealloc_type_int64;
v->visitor.type_uint64 = qapi_dealloc_type_uint64;
v->visitor.type_bool = qapi_dealloc_type_bool;
v->visitor.type_str = qapi_dealloc_type_str;
v->visitor.type_number = qapi_dealloc_type_number;
v->visitor.type_any = qapi_dealloc_type_anything;
2016-04-28 23:45:22 +02:00
v->visitor.type_null = qapi_dealloc_type_null;
QTAILQ_INIT(&v->stack);
return v;
}