qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

qapi: Add new visit_complete() function

Making each output visitor provide its own output collection
function was the only remaining reason for exposing visitor
sub-types to the rest of the code base. Add a polymorphic
visit_complete() function which is a no-op for input visitors,
and which populates an opaque pointer for output visitors. For
maximum type-safety, also add a parameter to the output visitor
constructors with a type-correct version of the output pointer,
and assert that the two uses match.

This approach was considered superior to either passing the
output parameter only during construction (action at a distance
during visit_free() feels awkward) or only during visit_complete()
(defeating type safety makes it easier to use incorrectly).

Most callers were function-local, and therefore a mechanical
conversion; the testsuite was a bit trickier, but the previous
cleanup patch minimized the churn here.

The visit_complete() function may be called at most once; doing
so lets us use transfer semantics rather than duplication or
ref-count semantics to get the just-built output back to the
caller, even though it means our behavior is not idempotent.

Generated code is simplified as follows for events:

|@@ -26,7 +26,7 @@ void qapi_event_send_acpi_device_ost(ACP
| QDict *qmp;
| Error *err = NULL;
| QMPEventFuncEmit emit;
|- QmpOutputVisitor *qov;
|+ QObject *obj;
| Visitor *v;
| q_obj_ACPI_DEVICE_OST_arg param = {
| info
|@@ -39,8 +39,7 @@ void qapi_event_send_acpi_device_ost(ACP
|
| qmp = qmp_event_build_dict("ACPI_DEVICE_OST");
|
|- qov = qmp_output_visitor_new();
|- v = qmp_output_get_visitor(qov);
|+ v = qmp_output_visitor_new(&obj);
|
| visit_start_struct(v, "ACPI_DEVICE_OST", NULL, 0, &err);
| if (err) {
|@@ -55,7 +54,8 @@ void qapi_event_send_acpi_device_ost(ACP
| goto out;
| }
|
|- qdict_put_obj(qmp, "data", qmp_output_get_qobject(qov));
|+ visit_complete(v, &obj);
|+ qdict_put_obj(qmp, "data", obj);
| emit(QAPI_EVENT_ACPI_DEVICE_OST, qmp, &err);

and for commands:

| {
| Error *err = NULL;
|- QmpOutputVisitor *qov = qmp_output_visitor_new();
| Visitor *v;
|
|- v = qmp_output_get_visitor(qov);
|+ v = qmp_output_visitor_new(ret_out);
| visit_type_AddfdInfo(v, "unused", &ret_in, &err);
|- if (err) {
|- goto out;
|+ if (!err) {
|+ visit_complete(v, ret_out);
| }
|- *ret_out = qmp_output_get_qobject(qov);
|-
|-out:
| error_propagate(errp, err);

Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1465490926-28625-13-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>

authored by

Eric Blake and committed by
Markus Armbruster
3b098d56 23d1705f

+166 -160
+4 -5
block/qapi.c
··· 690 690 void bdrv_image_info_specific_dump(fprintf_function func_fprintf, void *f, 691 691 ImageInfoSpecific *info_spec) 692 692 { 693 - QmpOutputVisitor *ov = qmp_output_visitor_new(); 694 693 QObject *obj, *data; 694 + Visitor *v = qmp_output_visitor_new(&obj); 695 695 696 - visit_type_ImageInfoSpecific(qmp_output_get_visitor(ov), NULL, &info_spec, 697 - &error_abort); 698 - obj = qmp_output_get_qobject(ov); 696 + visit_type_ImageInfoSpecific(v, NULL, &info_spec, &error_abort); 697 + visit_complete(v, &obj); 699 698 assert(qobject_type(obj) == QTYPE_QDICT); 700 699 data = qdict_get(qobject_to_qdict(obj), "data"); 701 700 dump_qobject(func_fprintf, f, 1, data); 702 - visit_free(qmp_output_get_visitor(ov)); 701 + visit_free(v); 703 702 } 704 703 705 704 void bdrv_image_info_dump(fprintf_function func_fprintf, void *f,
+4 -5
blockdev.c
··· 3950 3950 3951 3951 void qmp_blockdev_add(BlockdevOptions *options, Error **errp) 3952 3952 { 3953 - QmpOutputVisitor *ov = qmp_output_visitor_new(); 3954 3953 BlockDriverState *bs; 3955 3954 BlockBackend *blk = NULL; 3956 3955 QObject *obj; 3956 + Visitor *v = qmp_output_visitor_new(&obj); 3957 3957 QDict *qdict; 3958 3958 Error *local_err = NULL; 3959 3959 ··· 3972 3972 } 3973 3973 } 3974 3974 3975 - visit_type_BlockdevOptions(qmp_output_get_visitor(ov), NULL, &options, 3976 - &local_err); 3975 + visit_type_BlockdevOptions(v, NULL, &options, &local_err); 3977 3976 if (local_err) { 3978 3977 error_propagate(errp, local_err); 3979 3978 goto fail; 3980 3979 } 3981 3980 3982 - obj = qmp_output_get_qobject(ov); 3981 + visit_complete(v, &obj); 3983 3982 qdict = qobject_to_qdict(obj); 3984 3983 3985 3984 qdict_flatten(qdict); ··· 4020 4019 } 4021 4020 4022 4021 fail: 4023 - visit_free(qmp_output_get_visitor(ov)); 4022 + visit_free(v); 4024 4023 } 4025 4024 4026 4025 void qmp_x_blockdev_del(bool has_id, const char *id,
+3 -7
docs/qapi-code-gen.txt
··· 980 980 static void qmp_marshal_output_UserDefOne(UserDefOne *ret_in, QObject **ret_out, Error **errp) 981 981 { 982 982 Error *err = NULL; 983 - QmpOutputVisitor *qov = qmp_output_visitor_new(); 984 983 Visitor *v; 985 984 986 - v = qmp_output_get_visitor(qov); 985 + v = qmp_output_visitor_new(ret_out); 987 986 visit_type_UserDefOne(v, "unused", &ret_in, &err); 988 - if (err) { 989 - goto out; 987 + if (!err) { 988 + visit_complete(v, ret_out); 990 989 } 991 - *ret_out = qmp_output_get_qobject(qov); 992 - 993 - out: 994 990 error_propagate(errp, err); 995 991 visit_free(v); 996 992 v = qapi_dealloc_visitor_new();
+5 -6
hmp.c
··· 1983 1983 Error *err = NULL; 1984 1984 MemdevList *memdev_list = qmp_query_memdev(&err); 1985 1985 MemdevList *m = memdev_list; 1986 - StringOutputVisitor *ov; 1986 + Visitor *v; 1987 1987 char *str; 1988 1988 int i = 0; 1989 1989 1990 1990 1991 1991 while (m) { 1992 - ov = string_output_visitor_new(false); 1993 - visit_type_uint16List(string_output_get_visitor(ov), NULL, 1994 - &m->value->host_nodes, NULL); 1992 + v = string_output_visitor_new(false, &str); 1993 + visit_type_uint16List(v, NULL, &m->value->host_nodes, NULL); 1995 1994 monitor_printf(mon, "memory backend: %d\n", i); 1996 1995 monitor_printf(mon, " size: %" PRId64 "\n", m->value->size); 1997 1996 monitor_printf(mon, " merge: %s\n", ··· 2002 2001 m->value->prealloc ? "true" : "false"); 2003 2002 monitor_printf(mon, " policy: %s\n", 2004 2003 HostMemPolicy_lookup[m->value->policy]); 2005 - str = string_output_get_string(ov); 2004 + visit_complete(v, &str); 2006 2005 monitor_printf(mon, " host nodes: %s\n", str); 2007 2006 2008 2007 g_free(str); 2009 - visit_free(string_output_get_visitor(ov)); 2008 + visit_free(v); 2010 2009 m = m->next; 2011 2010 i++; 2012 2011 }
+7 -4
include/qapi/qmp-output-visitor.h
··· 19 19 20 20 typedef struct QmpOutputVisitor QmpOutputVisitor; 21 21 22 - QmpOutputVisitor *qmp_output_visitor_new(void); 23 - 24 - QObject *qmp_output_get_qobject(QmpOutputVisitor *v); 25 - Visitor *qmp_output_get_visitor(QmpOutputVisitor *v); 22 + /* 23 + * Create a new QMP output visitor. 24 + * 25 + * If everything else succeeds, pass @result to visit_complete() to 26 + * collect the result of the visit. 27 + */ 28 + Visitor *qmp_output_visitor_new(QObject **result); 26 29 27 30 #endif
+9 -4
include/qapi/string-output-visitor.h
··· 18 18 typedef struct StringOutputVisitor StringOutputVisitor; 19 19 20 20 /* 21 + * Create a new string output visitor. 22 + * 23 + * Using @human creates output that is a bit easier for humans to read 24 + * (for example, showing integer values in both decimal and hex). 25 + * 26 + * If everything else succeeds, pass @result to visit_complete() to 27 + * collect the result of the visit. 28 + * 21 29 * The string output visitor does not implement support for visiting 22 30 * QAPI structs, alternates, null, or arbitrary QTypes. It also 23 31 * requires a non-null list argument to visit_start_list(). 24 32 */ 25 - StringOutputVisitor *string_output_visitor_new(bool human); 26 - 27 - char *string_output_get_string(StringOutputVisitor *v); 28 - Visitor *string_output_get_visitor(StringOutputVisitor *v); 33 + Visitor *string_output_visitor_new(bool human, char **result); 29 34 30 35 #endif
+3
include/qapi/visitor-impl.h
··· 105 105 /* Must be set */ 106 106 VisitorType type; 107 107 108 + /* Must be set for output visitors, optional otherwise. */ 109 + void (*complete)(Visitor *v, void *opaque); 110 + 108 111 /* Must be set */ 109 112 void (*free)(Visitor *v); 110 113 };
+30 -20
include/qapi/visitor.h
··· 39 39 * 40 40 * All of the visitors are created via: 41 41 * 42 - * Type *subtype_visitor_new(parameters...); 43 - * 44 - * where Type is either directly 'Visitor *', or is a subtype that can 45 - * be trivially upcast to Visitor * via another function: 46 - * 47 - * Visitor *subtype_get_visitor(SubtypeVisitor *); 42 + * Visitor *subtype_visitor_new(parameters...); 48 43 * 49 44 * A visitor should be used for exactly one top-level visit_type_FOO() 50 - * or virtual walk, then passed to visit_free() to clean up resources. 45 + * or virtual walk; if that is successful, the caller can optionally 46 + * call visit_complete() (for now, useful only for output visits, but 47 + * safe to call on all visits). Then, regardless of success or 48 + * failure, the user should call visit_free() to clean up resources. 51 49 * It is okay to free the visitor without completing the visit, if 52 - * some other error is detected in the meantime. Output visitors 53 - * provide an additional function, for collecting the final results of 54 - * a successful visit: string_output_get_string() and 55 - * qmp_output_get_qobject(); this collection function should not be 56 - * called if any errors were reported during the visit. 50 + * some other error is detected in the meantime. 57 51 * 58 52 * All QAPI types have a corresponding function with a signature 59 53 * roughly compatible with this: ··· 123 117 * Error *err = NULL; 124 118 * Visitor *v; 125 119 * 126 - * v = ...obtain input visitor... 120 + * v = FOO_visitor_new(...); 127 121 * visit_type_Foo(v, NULL, &f, &err); 128 122 * if (err) { 129 123 * ...handle error... 130 124 * } else { 131 125 * ...use f... 132 126 * } 133 - * ...clean up v... 127 + * visit_free(v); 134 128 * qapi_free_Foo(f); 135 129 * </example> 136 130 * ··· 140 134 * Error *err = NULL; 141 135 * Visitor *v; 142 136 * 143 - * v = ...obtain input visitor... 137 + * v = FOO_visitor_new(...); 144 138 * visit_type_FooList(v, NULL, &l, &err); 145 139 * if (err) { 146 140 * ...handle error... ··· 149 143 * ...use l->value... 150 144 * } 151 145 * } 152 - * ...clean up v... 146 + * visit_free(v); 153 147 * qapi_free_FooList(l); 154 148 * </example> 155 149 * ··· 159 153 * Foo *f = ...obtain populated object... 160 154 * Error *err = NULL; 161 155 * Visitor *v; 156 + * Type *result; 162 157 * 163 - * v = ...obtain output visitor... 158 + * v = FOO_visitor_new(..., &result); 164 159 * visit_type_Foo(v, NULL, &f, &err); 165 160 * if (err) { 166 161 * ...handle error... 162 + * } else { 163 + * visit_complete(v, &result); 164 + * ...use result... 167 165 * } 168 - * ...clean up v... 166 + * visit_free(v); 169 167 * </example> 170 168 * 171 169 * When visiting a real QAPI struct, this file provides several ··· 191 189 * Error *err = NULL; 192 190 * int value; 193 191 * 194 - * v = ...obtain visitor... 192 + * v = FOO_visitor_new(...); 195 193 * visit_start_struct(v, NULL, NULL, 0, &err); 196 194 * if (err) { 197 195 * goto out; ··· 219 217 * visit_end_struct(v, NULL); 220 218 * out: 221 219 * error_propagate(errp, err); 222 - * ...clean up v... 220 + * visit_free(v); 223 221 * </example> 224 222 */ 225 223 ··· 241 239 } GenericAlternate; 242 240 243 241 /*** Visitor cleanup ***/ 242 + 243 + /* 244 + * Complete the visit, collecting any output. 245 + * 246 + * May only be called only once after a successful top-level 247 + * visit_type_FOO() or visit_end_ITEM(), and marks the end of the 248 + * visit. The @opaque pointer should match the output parameter 249 + * passed to the subtype_visitor_new() used to create an output 250 + * visitor, or NULL for any other visitor. Needed for output 251 + * visitors, but may also be called with other visitors. 252 + */ 253 + void visit_complete(Visitor *v, void *opaque); 244 254 245 255 /* 246 256 * Free @v and any resources it has tied up.
+5 -6
net/net.c
··· 1198 1198 char *str; 1199 1199 ObjectProperty *prop; 1200 1200 ObjectPropertyIterator iter; 1201 - StringOutputVisitor *ov; 1201 + Visitor *v; 1202 1202 1203 1203 /* generate info str */ 1204 1204 object_property_iter_init(&iter, OBJECT(nf)); ··· 1206 1206 if (!strcmp(prop->name, "type")) { 1207 1207 continue; 1208 1208 } 1209 - ov = string_output_visitor_new(false); 1210 - object_property_get(OBJECT(nf), string_output_get_visitor(ov), 1211 - prop->name, NULL); 1212 - str = string_output_get_string(ov); 1213 - visit_free(string_output_get_visitor(ov)); 1209 + v = string_output_visitor_new(false, &str); 1210 + object_property_get(OBJECT(nf), v, prop->name, NULL); 1211 + visit_complete(v, &str); 1212 + visit_free(v); 1214 1213 monitor_printf(mon, ",%s=%s", prop->name, str); 1215 1214 g_free(str); 1216 1215 }
+8
qapi/qapi-visit-core.c
··· 20 20 #include "qapi/visitor.h" 21 21 #include "qapi/visitor-impl.h" 22 22 23 + void visit_complete(Visitor *v, void *opaque) 24 + { 25 + assert(v->type != VISITOR_OUTPUT || v->complete); 26 + if (v->complete) { 27 + v->complete(v, opaque); 28 + } 29 + } 30 + 23 31 void visit_free(Visitor *v) 24 32 { 25 33 if (v) {
+12 -9
qapi/qmp-output-visitor.c
··· 33 33 Visitor visitor; 34 34 QStack stack; /* Stack of containers that haven't yet been finished */ 35 35 QObject *root; /* Root of the output visit */ 36 + QObject **result; /* User's storage location for result */ 36 37 }; 37 38 38 39 #define qmp_output_add(qov, name, value) \ ··· 200 201 /* Finish building, and return the root object. 201 202 * The root object is never null. The caller becomes the object's 202 203 * owner, and should use qobject_decref() when done with it. */ 203 - QObject *qmp_output_get_qobject(QmpOutputVisitor *qov) 204 + static void qmp_output_complete(Visitor *v, void *opaque) 204 205 { 206 + QmpOutputVisitor *qov = to_qov(v); 207 + 205 208 /* A visit must have occurred, with each start paired with end. */ 206 209 assert(qov->root && QTAILQ_EMPTY(&qov->stack)); 210 + assert(opaque == qov->result); 207 211 208 212 qobject_incref(qov->root); 209 - return qov->root; 210 - } 211 - 212 - Visitor *qmp_output_get_visitor(QmpOutputVisitor *v) 213 - { 214 - return &v->visitor; 213 + *qov->result = qov->root; 214 + qov->result = NULL; 215 215 } 216 216 217 217 static void qmp_output_free(Visitor *v) ··· 228 228 g_free(qov); 229 229 } 230 230 231 - QmpOutputVisitor *qmp_output_visitor_new(void) 231 + Visitor *qmp_output_visitor_new(QObject **result) 232 232 { 233 233 QmpOutputVisitor *v; 234 234 ··· 247 247 v->visitor.type_number = qmp_output_type_number; 248 248 v->visitor.type_any = qmp_output_type_any; 249 249 v->visitor.type_null = qmp_output_type_null; 250 + v->visitor.complete = qmp_output_complete; 250 251 v->visitor.free = qmp_output_free; 251 252 252 253 QTAILQ_INIT(&v->stack); 254 + *result = NULL; 255 + v->result = result; 253 256 254 - return v; 257 + return &v->visitor; 255 258 }
+12 -10
qapi/string-output-visitor.c
··· 58 58 Visitor visitor; 59 59 bool human; 60 60 GString *string; 61 + char **result; 61 62 ListMode list_mode; 62 63 union { 63 64 int64_t s; ··· 305 306 sov->list_mode = LM_NONE; 306 307 } 307 308 308 - char *string_output_get_string(StringOutputVisitor *sov) 309 + static void string_output_complete(Visitor *v, void *opaque) 309 310 { 310 - char *string = g_string_free(sov->string, false); 311 + StringOutputVisitor *sov = to_sov(v); 312 + 313 + assert(opaque == sov->result); 314 + *sov->result = g_string_free(sov->string, false); 311 315 sov->string = NULL; 312 - return string; 313 - } 314 - 315 - Visitor *string_output_get_visitor(StringOutputVisitor *sov) 316 - { 317 - return &sov->visitor; 318 316 } 319 317 320 318 static void free_range(void *range, void *dummy) ··· 335 333 g_free(sov); 336 334 } 337 335 338 - StringOutputVisitor *string_output_visitor_new(bool human) 336 + Visitor *string_output_visitor_new(bool human, char **result) 339 337 { 340 338 StringOutputVisitor *v; 341 339 ··· 343 341 344 342 v->string = g_string_new(NULL); 345 343 v->human = human; 344 + v->result = result; 345 + *result = NULL; 346 + 346 347 v->visitor.type = VISITOR_OUTPUT; 347 348 v->visitor.type_int64 = print_type_int64; 348 349 v->visitor.type_uint64 = print_type_uint64; ··· 353 354 v->visitor.start_list = start_list; 354 355 v->visitor.next_list = next_list; 355 356 v->visitor.end_list = end_list; 357 + v->visitor.complete = string_output_complete; 356 358 v->visitor.free = string_output_free; 357 359 358 - return v; 360 + return &v->visitor; 359 361 }
+15 -15
qemu-img.c
··· 491 491 static void dump_json_image_check(ImageCheck *check, bool quiet) 492 492 { 493 493 QString *str; 494 - QmpOutputVisitor *ov = qmp_output_visitor_new(); 495 494 QObject *obj; 496 - visit_type_ImageCheck(qmp_output_get_visitor(ov), NULL, &check, 497 - &error_abort); 498 - obj = qmp_output_get_qobject(ov); 495 + Visitor *v = qmp_output_visitor_new(&obj); 496 + 497 + visit_type_ImageCheck(v, NULL, &check, &error_abort); 498 + visit_complete(v, &obj); 499 499 str = qobject_to_json_pretty(obj); 500 500 assert(str != NULL); 501 501 qprintf(quiet, "%s\n", qstring_get_str(str)); 502 502 qobject_decref(obj); 503 - visit_free(qmp_output_get_visitor(ov)); 503 + visit_free(v); 504 504 QDECREF(str); 505 505 } 506 506 ··· 2181 2181 static void dump_json_image_info_list(ImageInfoList *list) 2182 2182 { 2183 2183 QString *str; 2184 - QmpOutputVisitor *ov = qmp_output_visitor_new(); 2185 2184 QObject *obj; 2186 - visit_type_ImageInfoList(qmp_output_get_visitor(ov), NULL, &list, 2187 - &error_abort); 2188 - obj = qmp_output_get_qobject(ov); 2185 + Visitor *v = qmp_output_visitor_new(&obj); 2186 + 2187 + visit_type_ImageInfoList(v, NULL, &list, &error_abort); 2188 + visit_complete(v, &obj); 2189 2189 str = qobject_to_json_pretty(obj); 2190 2190 assert(str != NULL); 2191 2191 printf("%s\n", qstring_get_str(str)); 2192 2192 qobject_decref(obj); 2193 - visit_free(qmp_output_get_visitor(ov)); 2193 + visit_free(v); 2194 2194 QDECREF(str); 2195 2195 } 2196 2196 2197 2197 static void dump_json_image_info(ImageInfo *info) 2198 2198 { 2199 2199 QString *str; 2200 - QmpOutputVisitor *ov = qmp_output_visitor_new(); 2201 2200 QObject *obj; 2202 - visit_type_ImageInfo(qmp_output_get_visitor(ov), NULL, &info, 2203 - &error_abort); 2204 - obj = qmp_output_get_qobject(ov); 2201 + Visitor *v = qmp_output_visitor_new(&obj); 2202 + 2203 + visit_type_ImageInfo(v, NULL, &info, &error_abort); 2204 + visit_complete(v, &obj); 2205 2205 str = qobject_to_json_pretty(obj); 2206 2206 assert(str != NULL); 2207 2207 printf("%s\n", qstring_get_str(str)); 2208 2208 qobject_decref(obj); 2209 - visit_free(qmp_output_get_visitor(ov)); 2209 + visit_free(v); 2210 2210 QDECREF(str); 2211 2211 } 2212 2212
+12 -16
qom/object.c
··· 1221 1221 const char *typename, Error **errp) 1222 1222 { 1223 1223 Error *err = NULL; 1224 - StringOutputVisitor *sov; 1225 1224 Visitor *v; 1226 1225 char *str; 1227 1226 int ret; ··· 1241 1240 1242 1241 enumprop = prop->opaque; 1243 1242 1244 - sov = string_output_visitor_new(false); 1245 - v = string_output_get_visitor(sov); 1243 + v = string_output_visitor_new(false, &str); 1246 1244 object_property_get(obj, v, name, &err); 1247 1245 if (err) { 1248 1246 error_propagate(errp, err); 1249 1247 visit_free(v); 1250 1248 return 0; 1251 1249 } 1252 - str = string_output_get_string(sov); 1250 + visit_complete(v, &str); 1253 1251 visit_free(v); 1254 1252 v = string_input_visitor_new(str); 1255 1253 visit_type_enum(v, name, &ret, enumprop->strings, errp); ··· 1264 1262 uint16List **list, Error **errp) 1265 1263 { 1266 1264 Error *err = NULL; 1267 - StringOutputVisitor *ov; 1268 1265 Visitor *v; 1269 1266 char *str; 1270 1267 1271 - ov = string_output_visitor_new(false); 1272 - object_property_get(obj, string_output_get_visitor(ov), 1273 - name, &err); 1268 + v = string_output_visitor_new(false, &str); 1269 + object_property_get(obj, v, name, &err); 1274 1270 if (err) { 1275 1271 error_propagate(errp, err); 1276 1272 goto out; 1277 1273 } 1278 - str = string_output_get_string(ov); 1274 + visit_complete(v, &str); 1275 + visit_free(v); 1279 1276 v = string_input_visitor_new(str); 1280 1277 visit_type_uint16List(v, NULL, list, errp); 1281 1278 1282 1279 g_free(str); 1283 - visit_free(v); 1284 1280 out: 1285 - visit_free(string_output_get_visitor(ov)); 1281 + visit_free(v); 1286 1282 } 1287 1283 1288 1284 void object_property_parse(Object *obj, const char *string, ··· 1296 1292 char *object_property_print(Object *obj, const char *name, bool human, 1297 1293 Error **errp) 1298 1294 { 1299 - StringOutputVisitor *sov; 1295 + Visitor *v; 1300 1296 char *string = NULL; 1301 1297 Error *local_err = NULL; 1302 1298 1303 - sov = string_output_visitor_new(human); 1304 - object_property_get(obj, string_output_get_visitor(sov), name, &local_err); 1299 + v = string_output_visitor_new(human, &string); 1300 + object_property_get(obj, v, name, &local_err); 1305 1301 if (local_err) { 1306 1302 error_propagate(errp, local_err); 1307 1303 goto out; 1308 1304 } 1309 1305 1310 - string = string_output_get_string(sov); 1306 + visit_complete(v, &string); 1311 1307 1312 1308 out: 1313 - visit_free(string_output_get_visitor(sov)); 1309 + visit_free(v); 1314 1310 return string; 1315 1311 } 1316 1312
+5 -5
qom/qom-qobject.c
··· 33 33 { 34 34 QObject *ret = NULL; 35 35 Error *local_err = NULL; 36 - QmpOutputVisitor *qov; 36 + Visitor *v; 37 37 38 - qov = qmp_output_visitor_new(); 39 - object_property_get(obj, qmp_output_get_visitor(qov), name, &local_err); 38 + v = qmp_output_visitor_new(&ret); 39 + object_property_get(obj, v, name, &local_err); 40 40 if (!local_err) { 41 - ret = qmp_output_get_qobject(qov); 41 + visit_complete(v, &ret); 42 42 } 43 43 error_propagate(errp, local_err); 44 - visit_free(qmp_output_get_visitor(qov)); 44 + visit_free(v); 45 45 return ret; 46 46 }
+2 -4
replay/replay-input.c
··· 22 22 23 23 static InputEvent *qapi_clone_InputEvent(InputEvent *src) 24 24 { 25 - QmpOutputVisitor *qov; 26 25 Visitor *ov, *iv; 27 26 QObject *obj; 28 27 InputEvent *dst = NULL; 29 28 30 - qov = qmp_output_visitor_new(); 31 - ov = qmp_output_get_visitor(qov); 29 + ov = qmp_output_visitor_new(&obj); 32 30 visit_type_InputEvent(ov, NULL, &src, &error_abort); 33 - obj = qmp_output_get_qobject(qov); 31 + visit_complete(ov, &obj); 34 32 visit_free(ov); 35 33 if (!obj) { 36 34 return NULL;
+3 -7
scripts/qapi-commands.py
··· 61 61 static void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in, QObject **ret_out, Error **errp) 62 62 { 63 63 Error *err = NULL; 64 - QmpOutputVisitor *qov = qmp_output_visitor_new(); 65 64 Visitor *v; 66 65 67 - v = qmp_output_get_visitor(qov); 66 + v = qmp_output_visitor_new(ret_out); 68 67 visit_type_%(c_name)s(v, "unused", &ret_in, &err); 69 - if (err) { 70 - goto out; 68 + if (!err) { 69 + visit_complete(v, ret_out); 71 70 } 72 - *ret_out = qmp_output_get_qobject(qov); 73 - 74 - out: 75 71 error_propagate(errp, err); 76 72 visit_free(v); 77 73 v = qapi_dealloc_visitor_new();
+4 -4
scripts/qapi-event.py
··· 71 71 72 72 if arg_type and arg_type.members: 73 73 ret += mcgen(''' 74 - QmpOutputVisitor *qov; 74 + QObject *obj; 75 75 Visitor *v; 76 76 ''') 77 77 ret += gen_param_var(arg_type) ··· 90 90 91 91 if arg_type and arg_type.members: 92 92 ret += mcgen(''' 93 - qov = qmp_output_visitor_new(); 94 - v = qmp_output_get_visitor(qov); 93 + v = qmp_output_visitor_new(&obj); 95 94 96 95 visit_start_struct(v, "%(name)s", NULL, 0, &err); 97 96 if (err) { ··· 106 105 goto out; 107 106 } 108 107 109 - qdict_put_obj(qmp, "data", qmp_output_get_qobject(qov)); 108 + visit_complete(v, &obj); 109 + qdict_put_obj(qmp, "data", obj); 110 110 ''', 111 111 name=name, c_name=arg_type.c_name()) 112 112
+4 -5
tests/check-qnull.c
··· 37 37 static void qnull_visit_test(void) 38 38 { 39 39 QObject *obj; 40 - QmpOutputVisitor *qov; 41 40 Visitor *v; 42 41 43 42 /* ··· 53 52 visit_type_null(v, NULL, &error_abort); 54 53 visit_free(v); 55 54 56 - qov = qmp_output_visitor_new(); 57 - visit_type_null(qmp_output_get_visitor(qov), NULL, &error_abort); 58 - obj = qmp_output_get_qobject(qov); 55 + v = qmp_output_visitor_new(&obj); 56 + visit_type_null(v, NULL, &error_abort); 57 + visit_complete(v, &obj); 59 58 g_assert(obj == &qnull_); 60 59 qobject_decref(obj); 61 - visit_free(qmp_output_get_visitor(qov)); 60 + visit_free(v); 62 61 63 62 g_assert(qnull_.refcnt == 1); 64 63 }
+3 -8
tests/test-qmp-output-visitor.c
··· 21 21 #include "qapi/qmp/qjson.h" 22 22 23 23 typedef struct TestOutputVisitorData { 24 - QmpOutputVisitor *qov; 25 24 Visitor *ov; 26 25 QObject *obj; 27 26 } TestOutputVisitorData; ··· 29 28 static void visitor_output_setup(TestOutputVisitorData *data, 30 29 const void *unused) 31 30 { 32 - data->qov = qmp_output_visitor_new(); 33 - g_assert(data->qov != NULL); 34 - 35 - data->ov = qmp_output_get_visitor(data->qov); 36 - g_assert(data->ov != NULL); 31 + data->ov = qmp_output_visitor_new(&data->obj); 32 + g_assert(data->ov); 37 33 } 38 34 39 35 static void visitor_output_teardown(TestOutputVisitorData *data, 40 36 const void *unused) 41 37 { 42 38 visit_free(data->ov); 43 - data->qov = NULL; 44 39 data->ov = NULL; 45 40 qobject_decref(data->obj); 46 41 data->obj = NULL; ··· 48 43 49 44 static QObject *visitor_get(TestOutputVisitorData *data) 50 45 { 51 - data->obj = qmp_output_get_qobject(data->qov); 46 + visit_complete(data->ov, &data->obj); 52 47 g_assert(data->obj); 53 48 return data->obj; 54 49 }
+2 -6
tests/test-string-output-visitor.c
··· 20 20 #include "qapi/qmp/types.h" 21 21 22 22 typedef struct TestOutputVisitorData { 23 - StringOutputVisitor *sov; 24 23 Visitor *ov; 25 24 char *str; 26 25 bool human; ··· 30 29 bool human) 31 30 { 32 31 data->human = human; 33 - data->sov = string_output_visitor_new(human); 34 - g_assert(data->sov); 35 - data->ov = string_output_get_visitor(data->sov); 32 + data->ov = string_output_visitor_new(human, &data->str); 36 33 g_assert(data->ov); 37 34 } 38 35 ··· 52 49 const void *unused) 53 50 { 54 51 visit_free(data->ov); 55 - data->sov = NULL; 56 52 data->ov = NULL; 57 53 g_free(data->str); 58 54 data->str = NULL; ··· 60 56 61 57 static char *visitor_get(TestOutputVisitorData *data) 62 58 { 63 - data->str = string_output_get_string(data->sov); 59 + visit_complete(data->ov, &data->str); 64 60 g_assert(data->str); 65 61 return data->str; 66 62 }
+12 -10
tests/test-visitor-serialization.c
··· 1012 1012 /* visitor-specific op implementations */ 1013 1013 1014 1014 typedef struct QmpSerializeData { 1015 - QmpOutputVisitor *qov; 1015 + Visitor *qov; 1016 + QObject *obj; 1016 1017 Visitor *qiv; 1017 1018 } QmpSerializeData; 1018 1019 ··· 1021 1022 { 1022 1023 QmpSerializeData *d = g_malloc0(sizeof(*d)); 1023 1024 1024 - d->qov = qmp_output_visitor_new(); 1025 - visit(qmp_output_get_visitor(d->qov), &native_in, errp); 1025 + d->qov = qmp_output_visitor_new(&d->obj); 1026 + visit(d->qov, &native_in, errp); 1026 1027 *datap = d; 1027 1028 } 1028 1029 ··· 1033 1034 QString *output_json; 1034 1035 QObject *obj_orig, *obj; 1035 1036 1036 - obj_orig = qmp_output_get_qobject(d->qov); 1037 + visit_complete(d->qov, &d->obj); 1038 + obj_orig = d->obj; 1037 1039 output_json = qobject_to_json(obj_orig); 1038 1040 obj = qobject_from_json(qstring_get_str(output_json)); 1039 1041 ··· 1047 1049 static void qmp_cleanup(void *datap) 1048 1050 { 1049 1051 QmpSerializeData *d = datap; 1050 - visit_free(qmp_output_get_visitor(d->qov)); 1052 + visit_free(d->qov); 1051 1053 visit_free(d->qiv); 1052 1054 1053 1055 g_free(d); ··· 1055 1057 1056 1058 typedef struct StringSerializeData { 1057 1059 char *string; 1058 - StringOutputVisitor *sov; 1060 + Visitor *sov; 1059 1061 Visitor *siv; 1060 1062 } StringSerializeData; 1061 1063 ··· 1064 1066 { 1065 1067 StringSerializeData *d = g_malloc0(sizeof(*d)); 1066 1068 1067 - d->sov = string_output_visitor_new(false); 1068 - visit(string_output_get_visitor(d->sov), &native_in, errp); 1069 + d->sov = string_output_visitor_new(false, &d->string); 1070 + visit(d->sov, &native_in, errp); 1069 1071 *datap = d; 1070 1072 } 1071 1073 ··· 1074 1076 { 1075 1077 StringSerializeData *d = datap; 1076 1078 1077 - d->string = string_output_get_string(d->sov); 1079 + visit_complete(d->sov, &d->string); 1078 1080 d->siv = string_input_visitor_new(d->string); 1079 1081 visit(d->siv, native_out, errp); 1080 1082 } ··· 1083 1085 { 1084 1086 StringSerializeData *d = datap; 1085 1087 1086 - visit_free(string_output_get_visitor(d->sov)); 1088 + visit_free(d->sov); 1087 1089 visit_free(d->siv); 1088 1090 g_free(d->string); 1089 1091 g_free(d);
+2 -4
util/qemu-sockets.c
··· 1147 1147 void qapi_copy_SocketAddress(SocketAddress **p_dest, 1148 1148 SocketAddress *src) 1149 1149 { 1150 - QmpOutputVisitor *qov; 1151 1150 Visitor *ov, *iv; 1152 1151 QObject *obj; 1153 1152 1154 1153 *p_dest = NULL; 1155 1154 1156 - qov = qmp_output_visitor_new(); 1157 - ov = qmp_output_get_visitor(qov); 1155 + ov = qmp_output_visitor_new(&obj); 1158 1156 visit_type_SocketAddress(ov, NULL, &src, &error_abort); 1159 - obj = qmp_output_get_qobject(qov); 1157 + visit_complete(ov, &obj); 1160 1158 visit_free(ov); 1161 1159 if (!obj) { 1162 1160 return;