QAPI patches for 2015-12-17

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJWcmVVAAoJEDhwtADrkYZTgLwP/2xkMCMhqvepE/wVM7MNygn8
 F1KuOd+9Qtt9mhr1MZlBmP1FRMhgIxQ3Ue0HHDTkPfKIem5titibk7YkVYXVDdYC
 xavxwfLlk7f3PlrzPrF19RnWRGUl5QZ0n914ZFNo0pbT+S9yVFkKMtXvcCHsP/RE
 f069rFIvJhzGa6gbL+FUkE4SO1SGzV/0xBDgrkUpoezrb23YA4EQKMKFRjPZkraH
 0rY3YNrAsKmHzMQlbkWhuhJ0LBoUoAJHle2ZYrk+cT1Gvn7TMH+6RPddwDNNXJrL
 guAHFdHKljnLqqcbBbcUydoWAMo0YqBbtme+E4GxcSbZiyz/M69eJ46Fyovge/mU
 pSxRAZChVl3fEACFYsAz42chip4exWHOLvOkODT+CYfVfAeVO5/pNtPi5Y77tJHo
 KKpDAsB/5XUkCRL9orhpo/g7noix1WUmZLFUPOgL6FWb6D6IHkZwX9f86BoFgvW0
 E30rRaSF4l1tATF723AEYKFG41a10iLCkaojy5s+jFPNP77qdvHoHQqtUSjAJyNz
 bpdEOKt/SLvr4rEYkGf1IJ4Pwvf5nS1yPpahY17dYHwNnHh/ngWCAy18A1to+ACg
 rNiOw17mJkIe3vBydiy3X7xAq7DPrA39cpRAHoSij1tqPm6mNrpx89WqtfbLWMtY
 y7k/agDt/WWtUdC/cYmC
 =X75u
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2015-12-17' into staging

QAPI patches for 2015-12-17

# gpg: Signature made Thu 17 Dec 2015 07:33:41 GMT using RSA key ID EB918653
# gpg: Good signature from "Markus Armbruster <armbru@redhat.com>"
# gpg:                 aka "Markus Armbruster <armbru@pond.sub.org>"

* remotes/armbru/tags/pull-qapi-2015-12-17: (40 commits)
  qapi: Detect base class loops
  qapi: Move duplicate collision checks to schema check()
  qapi: Enforce (or whitelist) case conventions on qapi members
  qapi: Track enum values by QAPISchemaMember, not string
  qapi: Prepare new QAPISchemaMember base class
  qapi: Shorter visits of optional fields
  qapi: Simplify visits of optional fields
  qapi: Fix alternates that accept 'number' but not 'int'
  qapi: Inline _make_implicit_tag()
  qapi-types: Drop unnedeed ._fwdefn
  qapi: Simplify visiting of alternate types
  qapi: Convert QType into QAPI built-in enum type
  qobject: Rename qtype_code to QType
  qobject: Simplify QObject
  qapi: Change munging of CamelCase enum values
  qapi: Add alias for ErrorClass
  cpu: Convert CpuInfo into flat union
  qapi: Remove obsolete tests for MAX collision
  qapi: Don't let implicit enum MAX member collide
  qapi: Tighten the regex on valid names
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2015-12-17 11:50:46 +00:00
commit c1a5f950cd
149 changed files with 847 additions and 879 deletions

View File

@ -2851,7 +2851,7 @@ ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs)
return NULL; return NULL;
} }
void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event) void bdrv_debug_event(BlockDriverState *bs, BlkdebugEvent event)
{ {
if (!bs || !bs->drv || !bs->drv->bdrv_debug_event) { if (!bs || !bs->drv || !bs->drv->bdrv_debug_event) {
return; return;

View File

@ -36,7 +36,7 @@ typedef struct BDRVBlkdebugState {
int state; int state;
int new_state; int new_state;
QLIST_HEAD(, BlkdebugRule) rules[BLKDBG_EVENT_MAX]; QLIST_HEAD(, BlkdebugRule) rules[BLKDBG__MAX];
QSIMPLEQ_HEAD(, BlkdebugRule) active_rules; QSIMPLEQ_HEAD(, BlkdebugRule) active_rules;
QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs; QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs;
} BDRVBlkdebugState; } BDRVBlkdebugState;
@ -64,7 +64,7 @@ enum {
}; };
typedef struct BlkdebugRule { typedef struct BlkdebugRule {
BlkDebugEvent event; BlkdebugEvent event;
int action; int action;
int state; int state;
union { union {
@ -143,69 +143,12 @@ static QemuOptsList *config_groups[] = {
NULL NULL
}; };
static const char *event_names[BLKDBG_EVENT_MAX] = { static int get_event_by_name(const char *name, BlkdebugEvent *event)
[BLKDBG_L1_UPDATE] = "l1_update",
[BLKDBG_L1_GROW_ALLOC_TABLE] = "l1_grow.alloc_table",
[BLKDBG_L1_GROW_WRITE_TABLE] = "l1_grow.write_table",
[BLKDBG_L1_GROW_ACTIVATE_TABLE] = "l1_grow.activate_table",
[BLKDBG_L2_LOAD] = "l2_load",
[BLKDBG_L2_UPDATE] = "l2_update",
[BLKDBG_L2_UPDATE_COMPRESSED] = "l2_update_compressed",
[BLKDBG_L2_ALLOC_COW_READ] = "l2_alloc.cow_read",
[BLKDBG_L2_ALLOC_WRITE] = "l2_alloc.write",
[BLKDBG_READ_AIO] = "read_aio",
[BLKDBG_READ_BACKING_AIO] = "read_backing_aio",
[BLKDBG_READ_COMPRESSED] = "read_compressed",
[BLKDBG_WRITE_AIO] = "write_aio",
[BLKDBG_WRITE_COMPRESSED] = "write_compressed",
[BLKDBG_VMSTATE_LOAD] = "vmstate_load",
[BLKDBG_VMSTATE_SAVE] = "vmstate_save",
[BLKDBG_COW_READ] = "cow_read",
[BLKDBG_COW_WRITE] = "cow_write",
[BLKDBG_REFTABLE_LOAD] = "reftable_load",
[BLKDBG_REFTABLE_GROW] = "reftable_grow",
[BLKDBG_REFTABLE_UPDATE] = "reftable_update",
[BLKDBG_REFBLOCK_LOAD] = "refblock_load",
[BLKDBG_REFBLOCK_UPDATE] = "refblock_update",
[BLKDBG_REFBLOCK_UPDATE_PART] = "refblock_update_part",
[BLKDBG_REFBLOCK_ALLOC] = "refblock_alloc",
[BLKDBG_REFBLOCK_ALLOC_HOOKUP] = "refblock_alloc.hookup",
[BLKDBG_REFBLOCK_ALLOC_WRITE] = "refblock_alloc.write",
[BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS] = "refblock_alloc.write_blocks",
[BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE] = "refblock_alloc.write_table",
[BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE] = "refblock_alloc.switch_table",
[BLKDBG_CLUSTER_ALLOC] = "cluster_alloc",
[BLKDBG_CLUSTER_ALLOC_BYTES] = "cluster_alloc_bytes",
[BLKDBG_CLUSTER_FREE] = "cluster_free",
[BLKDBG_FLUSH_TO_OS] = "flush_to_os",
[BLKDBG_FLUSH_TO_DISK] = "flush_to_disk",
[BLKDBG_PWRITEV_RMW_HEAD] = "pwritev_rmw.head",
[BLKDBG_PWRITEV_RMW_AFTER_HEAD] = "pwritev_rmw.after_head",
[BLKDBG_PWRITEV_RMW_TAIL] = "pwritev_rmw.tail",
[BLKDBG_PWRITEV_RMW_AFTER_TAIL] = "pwritev_rmw.after_tail",
[BLKDBG_PWRITEV] = "pwritev",
[BLKDBG_PWRITEV_ZERO] = "pwritev_zero",
[BLKDBG_PWRITEV_DONE] = "pwritev_done",
[BLKDBG_EMPTY_IMAGE_PREPARE] = "empty_image_prepare",
};
static int get_event_by_name(const char *name, BlkDebugEvent *event)
{ {
int i; int i;
for (i = 0; i < BLKDBG_EVENT_MAX; i++) { for (i = 0; i < BLKDBG__MAX; i++) {
if (!strcmp(event_names[i], name)) { if (!strcmp(BlkdebugEvent_lookup[i], name)) {
*event = i; *event = i;
return 0; return 0;
} }
@ -224,7 +167,7 @@ static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
struct add_rule_data *d = opaque; struct add_rule_data *d = opaque;
BDRVBlkdebugState *s = d->s; BDRVBlkdebugState *s = d->s;
const char* event_name; const char* event_name;
BlkDebugEvent event; BlkdebugEvent event;
struct BlkdebugRule *rule; struct BlkdebugRule *rule;
/* Find the right event for the rule */ /* Find the right event for the rule */
@ -564,7 +507,7 @@ static void blkdebug_close(BlockDriverState *bs)
BlkdebugRule *rule, *next; BlkdebugRule *rule, *next;
int i; int i;
for (i = 0; i < BLKDBG_EVENT_MAX; i++) { for (i = 0; i < BLKDBG__MAX; i++) {
QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) { QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
remove_rule(rule); remove_rule(rule);
} }
@ -627,13 +570,13 @@ static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
return injected; return injected;
} }
static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event) static void blkdebug_debug_event(BlockDriverState *bs, BlkdebugEvent event)
{ {
BDRVBlkdebugState *s = bs->opaque; BDRVBlkdebugState *s = bs->opaque;
struct BlkdebugRule *rule, *next; struct BlkdebugRule *rule, *next;
bool injected; bool injected;
assert((int)event >= 0 && event < BLKDBG_EVENT_MAX); assert((int)event >= 0 && event < BLKDBG__MAX);
injected = false; injected = false;
s->new_state = s->state; s->new_state = s->state;
@ -648,7 +591,7 @@ static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event,
{ {
BDRVBlkdebugState *s = bs->opaque; BDRVBlkdebugState *s = bs->opaque;
struct BlkdebugRule *rule; struct BlkdebugRule *rule;
BlkDebugEvent blkdebug_event; BlkdebugEvent blkdebug_event;
if (get_event_by_name(event, &blkdebug_event) < 0) { if (get_event_by_name(event, &blkdebug_event) < 0) {
return -ENOENT; return -ENOENT;
@ -690,7 +633,7 @@ static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs,
BlkdebugRule *rule, *next; BlkdebugRule *rule, *next;
int i, ret = -ENOENT; int i, ret = -ENOENT;
for (i = 0; i < BLKDBG_EVENT_MAX; i++) { for (i = 0; i < BLKDBG__MAX; i++) {
QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) { QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
if (rule->action == ACTION_SUSPEND && if (rule->action == ACTION_SUSPEND &&
!strcmp(rule->options.suspend.tag, tag)) { !strcmp(rule->options.suspend.tag, tag)) {

View File

@ -61,7 +61,7 @@ typedef struct ParallelsHeader {
typedef enum ParallelsPreallocMode { typedef enum ParallelsPreallocMode {
PRL_PREALLOC_MODE_FALLOCATE = 0, PRL_PREALLOC_MODE_FALLOCATE = 0,
PRL_PREALLOC_MODE_TRUNCATE = 1, PRL_PREALLOC_MODE_TRUNCATE = 1,
PRL_PREALLOC_MODE_MAX = 2, PRL_PREALLOC_MODE__MAX = 2,
} ParallelsPreallocMode; } ParallelsPreallocMode;
static const char *prealloc_mode_lookup[] = { static const char *prealloc_mode_lookup[] = {
@ -660,7 +660,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
s->prealloc_size = MAX(s->tracks, s->prealloc_size >> BDRV_SECTOR_BITS); s->prealloc_size = MAX(s->tracks, s->prealloc_size >> BDRV_SECTOR_BITS);
buf = qemu_opt_get_del(opts, PARALLELS_OPT_PREALLOC_MODE); buf = qemu_opt_get_del(opts, PARALLELS_OPT_PREALLOC_MODE);
s->prealloc_mode = qapi_enum_parse(prealloc_mode_lookup, buf, s->prealloc_mode = qapi_enum_parse(prealloc_mode_lookup, buf,
PRL_PREALLOC_MODE_MAX, PRL_PREALLOC_MODE_FALLOCATE, &local_err); PRL_PREALLOC_MODE__MAX, PRL_PREALLOC_MODE_FALLOCATE, &local_err);
g_free(buf); g_free(buf);
if (local_err != NULL) { if (local_err != NULL) {
goto fail_options; goto fail_options;

View File

@ -588,7 +588,7 @@ static void dump_qlist(fprintf_function func_fprintf, void *f, int indentation,
int i = 0; int i = 0;
for (entry = qlist_first(list); entry; entry = qlist_next(entry), i++) { for (entry = qlist_first(list); entry; entry = qlist_next(entry), i++) {
qtype_code type = qobject_type(entry->value); QType type = qobject_type(entry->value);
bool composite = (type == QTYPE_QDICT || type == QTYPE_QLIST); bool composite = (type == QTYPE_QDICT || type == QTYPE_QLIST);
const char *format = composite ? "%*s[%i]:\n" : "%*s[%i]: "; const char *format = composite ? "%*s[%i]:\n" : "%*s[%i]: ";
@ -606,7 +606,7 @@ static void dump_qdict(fprintf_function func_fprintf, void *f, int indentation,
const QDictEntry *entry; const QDictEntry *entry;
for (entry = qdict_first(dict); entry; entry = qdict_next(dict, entry)) { for (entry = qdict_first(dict); entry; entry = qdict_next(dict, entry)) {
qtype_code type = qobject_type(entry->value); QType type = qobject_type(entry->value);
bool composite = (type == QTYPE_QDICT || type == QTYPE_QLIST); bool composite = (type == QTYPE_QDICT || type == QTYPE_QLIST);
const char *format = composite ? "%*s%s:\n" : "%*s%s: "; const char *format = composite ? "%*s%s:\n" : "%*s%s: ";
char key[strlen(entry->key) + 1]; char key[strlen(entry->key) + 1];

View File

@ -2269,7 +2269,7 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
DEFAULT_CLUSTER_SIZE); DEFAULT_CLUSTER_SIZE);
buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC); buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
prealloc = qapi_enum_parse(PreallocMode_lookup, buf, prealloc = qapi_enum_parse(PreallocMode_lookup, buf,
PREALLOC_MODE_MAX, PREALLOC_MODE_OFF, PREALLOC_MODE__MAX, PREALLOC_MODE_OFF,
&local_err); &local_err);
if (local_err) { if (local_err) {
error_propagate(errp, local_err); error_propagate(errp, local_err);

View File

@ -847,7 +847,7 @@ static int parse_read_pattern(const char *opt)
return QUORUM_READ_PATTERN_QUORUM; return QUORUM_READ_PATTERN_QUORUM;
} }
for (i = 0; i < QUORUM_READ_PATTERN_MAX; i++) { for (i = 0; i < QUORUM_READ_PATTERN__MAX; i++) {
if (!strcmp(opt, QuorumReadPattern_lookup[i])) { if (!strcmp(opt, QuorumReadPattern_lookup[i])) {
return i; return i;
} }

View File

@ -1636,7 +1636,7 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
nocow = qemu_opt_get_bool(opts, BLOCK_OPT_NOCOW, false); nocow = qemu_opt_get_bool(opts, BLOCK_OPT_NOCOW, false);
buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC); buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
prealloc = qapi_enum_parse(PreallocMode_lookup, buf, prealloc = qapi_enum_parse(PreallocMode_lookup, buf,
PREALLOC_MODE_MAX, PREALLOC_MODE_OFF, PREALLOC_MODE__MAX, PREALLOC_MODE_OFF,
&local_err); &local_err);
g_free(buf); g_free(buf);
if (local_err) { if (local_err) {

View File

@ -454,7 +454,7 @@ static void extract_common_blockdev_options(QemuOpts *opts, int *bdrv_flags,
*detect_zeroes = *detect_zeroes =
qapi_enum_parse(BlockdevDetectZeroesOptions_lookup, qapi_enum_parse(BlockdevDetectZeroesOptions_lookup,
qemu_opt_get(opts, "detect-zeroes"), qemu_opt_get(opts, "detect-zeroes"),
BLOCKDEV_DETECT_ZEROES_OPTIONS_MAX, BLOCKDEV_DETECT_ZEROES_OPTIONS__MAX,
BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF, BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
&local_error); &local_error);
if (local_error) { if (local_error) {

31
cpus.c
View File

@ -1558,22 +1558,29 @@ CpuInfoList *qmp_query_cpus(Error **errp)
info->value->qom_path = object_get_canonical_path(OBJECT(cpu)); info->value->qom_path = object_get_canonical_path(OBJECT(cpu));
info->value->thread_id = cpu->thread_id; info->value->thread_id = cpu->thread_id;
#if defined(TARGET_I386) #if defined(TARGET_I386)
info->value->has_pc = true; info->value->arch = CPU_INFO_ARCH_X86;
info->value->pc = env->eip + env->segs[R_CS].base; info->value->u.x86 = g_new0(CpuInfoX86, 1);
info->value->u.x86->pc = env->eip + env->segs[R_CS].base;
#elif defined(TARGET_PPC) #elif defined(TARGET_PPC)
info->value->has_nip = true; info->value->arch = CPU_INFO_ARCH_PPC;
info->value->nip = env->nip; info->value->u.ppc = g_new0(CpuInfoPPC, 1);
info->value->u.ppc->nip = env->nip;
#elif defined(TARGET_SPARC) #elif defined(TARGET_SPARC)
info->value->has_pc = true; info->value->arch = CPU_INFO_ARCH_SPARC;
info->value->pc = env->pc; info->value->u.sparc = g_new0(CpuInfoSPARC, 1);
info->value->has_npc = true; info->value->u.sparc->pc = env->pc;
info->value->npc = env->npc; info->value->u.sparc->npc = env->npc;
#elif defined(TARGET_MIPS) #elif defined(TARGET_MIPS)
info->value->has_PC = true; info->value->arch = CPU_INFO_ARCH_MIPS;
info->value->PC = env->active_tc.PC; info->value->u.mips = g_new0(CpuInfoMIPS, 1);
info->value->u.mips->PC = env->active_tc.PC;
#elif defined(TARGET_TRICORE) #elif defined(TARGET_TRICORE)
info->value->has_PC = true; info->value->arch = CPU_INFO_ARCH_TRICORE;
info->value->PC = env->PC; info->value->u.tricore = g_new0(CpuInfoTricore, 1);
info->value->u.tricore->PC = env->PC;
#else
info->value->arch = CPU_INFO_ARCH_OTHER;
info->value->u.other = g_new0(CpuInfoOther, 1);
#endif #endif
/* XXX: waiting for the qapi to support GSList */ /* XXX: waiting for the qapi to support GSList */

View File

@ -1,6 +1,6 @@
Block I/O error injection using blkdebug Block I/O error injection using blkdebug
---------------------------------------- ----------------------------------------
Copyright (C) 2014 Red Hat Inc Copyright (C) 2014-2015 Red Hat Inc
This work is licensed under the terms of the GNU GPL, version 2 or later. See This work is licensed under the terms of the GNU GPL, version 2 or later. See
the COPYING file in the top-level directory. the COPYING file in the top-level directory.
@ -92,8 +92,9 @@ The core events are:
flush_to_disk - flush the host block device's disk cache flush_to_disk - flush the host block device's disk cache
See block/blkdebug.c:event_names[] for the full list of events. You may need See qapi/block-core.json:BlkdebugEvent for the full list of events.
to grep block driver source code to understand the meaning of specific events. You may need to grep block driver source code to understand the
meaning of specific events.
State transitions State transitions
----------------- -----------------

View File

@ -118,17 +118,17 @@ tracking optional fields.
Any name (command, event, type, field, or enum value) beginning with Any name (command, event, type, field, or enum value) beginning with
"x-" is marked experimental, and may be withdrawn or changed "x-" is marked experimental, and may be withdrawn or changed
incompatibly in a future release. Downstream vendors may add incompatibly in a future release. All names must begin with a letter,
extensions; such extensions should begin with a prefix matching and contain only ASCII letters, digits, dash, and underscore. There
"__RFQDN_" (for the reverse-fully-qualified-domain-name of the are two exceptions: enum values may start with a digit, and any
vendor), even if the rest of the name uses dash (example: extensions added by downstream vendors should start with a prefix
__com.redhat_drive-mirror). Other than downstream extensions (with matching "__RFQDN_" (for the reverse-fully-qualified-domain-name of
leading underscore and the use of dots), all names should begin with a the vendor), even if the rest of the name uses dash (example:
letter, and contain only ASCII letters, digits, dash, and underscore. __com.redhat_drive-mirror). Names beginning with 'q_' are reserved
Names beginning with 'q_' are reserved for the generator: QMP names for the generator: QMP names that resemble C keywords or other
that resemble C keywords or other problematic strings will be munged problematic strings will be munged in C to use this prefix. For
in C to use this prefix. For example, a field named "default" in example, a field named "default" in qapi becomes "q_default" in the
qapi becomes "q_default" in the generated C code. generated C code.
In the rest of this document, usage lines are given for each In the rest of this document, usage lines are given for each
expression type, with literal strings written in lower case and expression type, with literal strings written in lower case and
@ -160,6 +160,7 @@ The following types are predefined, and map to C as follows:
accepts size suffixes accepts size suffixes
bool bool JSON true or false bool bool JSON true or false
any QObject * any JSON value any QObject * any JSON value
QType QType JSON string matching enum QType values
=== Includes === === Includes ===
@ -383,9 +384,6 @@ where each branch of the union names a QAPI type. For example:
'data': { 'definition': 'BlockdevOptions', 'data': { 'definition': 'BlockdevOptions',
'reference': 'str' } } 'reference': 'str' } }
Just like for a simple union, an implicit C enum 'NameKind' is created
to enumerate the branches for the alternate 'Name'.
Unlike a union, the discriminator string is never passed on the wire Unlike a union, the discriminator string is never passed on the wire
for the Client JSON Protocol. Instead, the value's JSON type serves for the Client JSON Protocol. Instead, the value's JSON type serves
as an implicit discriminator, which in turn means that an alternate as an implicit discriminator, which in turn means that an alternate
@ -1053,7 +1051,7 @@ Example:
const char *const example_QAPIEvent_lookup[] = { const char *const example_QAPIEvent_lookup[] = {
[EXAMPLE_QAPI_EVENT_MY_EVENT] = "MY_EVENT", [EXAMPLE_QAPI_EVENT_MY_EVENT] = "MY_EVENT",
[EXAMPLE_QAPI_EVENT_MAX] = NULL, [EXAMPLE_QAPI_EVENT__MAX] = NULL,
}; };
$ cat qapi-generated/example-qapi-event.h $ cat qapi-generated/example-qapi-event.h
[Uninteresting stuff omitted...] [Uninteresting stuff omitted...]
@ -1070,7 +1068,7 @@ Example:
typedef enum example_QAPIEvent { typedef enum example_QAPIEvent {
EXAMPLE_QAPI_EVENT_MY_EVENT = 0, EXAMPLE_QAPI_EVENT_MY_EVENT = 0,
EXAMPLE_QAPI_EVENT_MAX = 1, EXAMPLE_QAPI_EVENT__MAX = 1,
} example_QAPIEvent; } example_QAPIEvent;
extern const char *const example_QAPIEvent_lookup[]; extern const char *const example_QAPIEvent_lookup[];

44
hmp.c
View File

@ -311,17 +311,25 @@ void hmp_info_cpus(Monitor *mon, const QDict *qdict)
monitor_printf(mon, "%c CPU #%" PRId64 ":", active, cpu->value->CPU); monitor_printf(mon, "%c CPU #%" PRId64 ":", active, cpu->value->CPU);
if (cpu->value->has_pc) { switch (cpu->value->arch) {
monitor_printf(mon, " pc=0x%016" PRIx64, cpu->value->pc); case CPU_INFO_ARCH_X86:
} monitor_printf(mon, " pc=0x%016" PRIx64, cpu->value->u.x86->pc);
if (cpu->value->has_nip) { break;
monitor_printf(mon, " nip=0x%016" PRIx64, cpu->value->nip); case CPU_INFO_ARCH_PPC:
} monitor_printf(mon, " nip=0x%016" PRIx64, cpu->value->u.ppc->nip);
if (cpu->value->has_npc) { break;
monitor_printf(mon, " npc=0x%016" PRIx64, cpu->value->npc); case CPU_INFO_ARCH_SPARC:
} monitor_printf(mon, " pc=0x%016" PRIx64, cpu->value->u.sparc->pc);
if (cpu->value->has_PC) { monitor_printf(mon, " npc=0x%016" PRIx64, cpu->value->u.sparc->npc);
monitor_printf(mon, " PC=0x%016" PRIx64, cpu->value->PC); break;
case CPU_INFO_ARCH_MIPS:
monitor_printf(mon, " PC=0x%016" PRIx64, cpu->value->u.mips->PC);
break;
case CPU_INFO_ARCH_TRICORE:
monitor_printf(mon, " PC=0x%016" PRIx64, cpu->value->u.tricore->PC);
break;
default:
break;
} }
if (cpu->value->halted) { if (cpu->value->halted) {
@ -855,7 +863,7 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)
tpo->has_cancel_path ? ",cancel-path=" : "", tpo->has_cancel_path ? ",cancel-path=" : "",
tpo->has_cancel_path ? tpo->cancel_path : ""); tpo->has_cancel_path ? tpo->cancel_path : "");
break; break;
case TPM_TYPE_OPTIONS_KIND_MAX: case TPM_TYPE_OPTIONS_KIND__MAX:
break; break;
} }
monitor_printf(mon, "\n"); monitor_printf(mon, "\n");
@ -1203,7 +1211,7 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
MigrationCapabilityStatusList *caps = g_malloc0(sizeof(*caps)); MigrationCapabilityStatusList *caps = g_malloc0(sizeof(*caps));
int i; int i;
for (i = 0; i < MIGRATION_CAPABILITY_MAX; i++) { for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
if (strcmp(cap, MigrationCapability_lookup[i]) == 0) { if (strcmp(cap, MigrationCapability_lookup[i]) == 0) {
caps->value = g_malloc0(sizeof(*caps->value)); caps->value = g_malloc0(sizeof(*caps->value));
caps->value->capability = i; caps->value->capability = i;
@ -1214,7 +1222,7 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
} }
} }
if (i == MIGRATION_CAPABILITY_MAX) { if (i == MIGRATION_CAPABILITY__MAX) {
error_setg(&err, QERR_INVALID_PARAMETER, cap); error_setg(&err, QERR_INVALID_PARAMETER, cap);
} }
@ -1239,7 +1247,7 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
bool has_x_cpu_throttle_increment = false; bool has_x_cpu_throttle_increment = false;
int i; int i;
for (i = 0; i < MIGRATION_PARAMETER_MAX; i++) { for (i = 0; i < MIGRATION_PARAMETER__MAX; i++) {
if (strcmp(param, MigrationParameter_lookup[i]) == 0) { if (strcmp(param, MigrationParameter_lookup[i]) == 0) {
switch (i) { switch (i) {
case MIGRATION_PARAMETER_COMPRESS_LEVEL: case MIGRATION_PARAMETER_COMPRESS_LEVEL:
@ -1268,7 +1276,7 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
} }
} }
if (i == MIGRATION_PARAMETER_MAX) { if (i == MIGRATION_PARAMETER__MAX) {
error_setg(&err, QERR_INVALID_PARAMETER, param); error_setg(&err, QERR_INVALID_PARAMETER, param);
} }
@ -1368,7 +1376,7 @@ void hmp_change(Monitor *mon, const QDict *qdict)
if (read_only) { if (read_only) {
read_only_mode = read_only_mode =
qapi_enum_parse(BlockdevChangeReadOnlyMode_lookup, qapi_enum_parse(BlockdevChangeReadOnlyMode_lookup,
read_only, BLOCKDEV_CHANGE_READ_ONLY_MODE_MAX, read_only, BLOCKDEV_CHANGE_READ_ONLY_MODE__MAX,
BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN, &err); BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN, &err);
if (err) { if (err) {
hmp_handle_error(mon, &err); hmp_handle_error(mon, &err);
@ -1771,7 +1779,7 @@ void hmp_sendkey(Monitor *mon, const QDict *qdict)
keylist->value->u.number = value; keylist->value->u.number = value;
} else { } else {
int idx = index_from_key(keyname_buf); int idx = index_from_key(keyname_buf);
if (idx == Q_KEY_CODE_MAX) { if (idx == Q_KEY_CODE__MAX) {
goto err_out; goto err_out;
} }
keylist->value->type = KEY_VALUE_KIND_QCODE; keylist->value->type = KEY_VALUE_KIND_QCODE;

View File

@ -714,7 +714,7 @@ MemoryRegion *escc_init(hwaddr base, qemu_irq irqA, qemu_irq irqB,
return &d->mmio; return &d->mmio;
} }
static const uint8_t qcode_to_keycode[Q_KEY_CODE_MAX] = { static const uint8_t qcode_to_keycode[Q_KEY_CODE__MAX] = {
[Q_KEY_CODE_SHIFT] = 99, [Q_KEY_CODE_SHIFT] = 99,
[Q_KEY_CODE_SHIFT_R] = 110, [Q_KEY_CODE_SHIFT_R] = 110,
[Q_KEY_CODE_ALT] = 19, [Q_KEY_CODE_ALT] = 19,

View File

@ -225,7 +225,7 @@ static void pc_init1(MachineState *machine,
pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL); pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL);
assert(pcms->vmport != ON_OFF_AUTO_MAX); assert(pcms->vmport != ON_OFF_AUTO__MAX);
if (pcms->vmport == ON_OFF_AUTO_AUTO) { if (pcms->vmport == ON_OFF_AUTO_AUTO) {
pcms->vmport = xen_enabled() ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON; pcms->vmport = xen_enabled() ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON;
} }

View File

@ -233,7 +233,7 @@ static void pc_q35_init(MachineState *machine)
pc_register_ferr_irq(gsi[13]); pc_register_ferr_irq(gsi[13]);
assert(pcms->vmport != ON_OFF_AUTO_MAX); assert(pcms->vmport != ON_OFF_AUTO__MAX);
if (pcms->vmport == ON_OFF_AUTO_AUTO) { if (pcms->vmport == ON_OFF_AUTO_AUTO) {
pcms->vmport = xen_enabled() ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON; pcms->vmport = xen_enabled() ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON;
} }

View File

@ -108,7 +108,7 @@ void hid_set_next_idle(HIDState *hs)
static void hid_pointer_event(DeviceState *dev, QemuConsole *src, static void hid_pointer_event(DeviceState *dev, QemuConsole *src,
InputEvent *evt) InputEvent *evt)
{ {
static const int bmap[INPUT_BUTTON_MAX] = { static const int bmap[INPUT_BUTTON__MAX] = {
[INPUT_BUTTON_LEFT] = 0x01, [INPUT_BUTTON_LEFT] = 0x01,
[INPUT_BUTTON_RIGHT] = 0x02, [INPUT_BUTTON_RIGHT] = 0x02,
[INPUT_BUTTON_MIDDLE] = 0x04, [INPUT_BUTTON_MIDDLE] = 0x04,
@ -139,9 +139,9 @@ static void hid_pointer_event(DeviceState *dev, QemuConsole *src,
case INPUT_EVENT_KIND_BTN: case INPUT_EVENT_KIND_BTN:
if (evt->u.btn->down) { if (evt->u.btn->down) {
e->buttons_state |= bmap[evt->u.btn->button]; e->buttons_state |= bmap[evt->u.btn->button];
if (evt->u.btn->button == INPUT_BUTTON_WHEEL_UP) { if (evt->u.btn->button == INPUT_BUTTON_WHEELUP) {
e->dz--; e->dz--;
} else if (evt->u.btn->button == INPUT_BUTTON_WHEEL_DOWN) { } else if (evt->u.btn->button == INPUT_BUTTON_WHEELDOWN) {
e->dz++; e->dz++;
} }
} else { } else {

View File

@ -382,7 +382,7 @@ static void ps2_mouse_send_packet(PS2MouseState *s)
static void ps2_mouse_event(DeviceState *dev, QemuConsole *src, static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
InputEvent *evt) InputEvent *evt)
{ {
static const int bmap[INPUT_BUTTON_MAX] = { static const int bmap[INPUT_BUTTON__MAX] = {
[INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON, [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
[INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON, [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
[INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON, [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
@ -405,9 +405,9 @@ static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
case INPUT_EVENT_KIND_BTN: case INPUT_EVENT_KIND_BTN:
if (evt->u.btn->down) { if (evt->u.btn->down) {
s->mouse_buttons |= bmap[evt->u.btn->button]; s->mouse_buttons |= bmap[evt->u.btn->button];
if (evt->u.btn->button == INPUT_BUTTON_WHEEL_UP) { if (evt->u.btn->button == INPUT_BUTTON_WHEELUP) {
s->mouse_dz--; s->mouse_dz--;
} else if (evt->u.btn->button == INPUT_BUTTON_WHEEL_DOWN) { } else if (evt->u.btn->button == INPUT_BUTTON_WHEELDOWN) {
s->mouse_dz++; s->mouse_dz++;
} }
} else { } else {

View File

@ -21,7 +21,7 @@
/* ----------------------------------------------------------------- */ /* ----------------------------------------------------------------- */
static const unsigned int keymap_qcode[Q_KEY_CODE_MAX] = { static const unsigned int keymap_qcode[Q_KEY_CODE__MAX] = {
[Q_KEY_CODE_ESC] = KEY_ESC, [Q_KEY_CODE_ESC] = KEY_ESC,
[Q_KEY_CODE_1] = KEY_1, [Q_KEY_CODE_1] = KEY_1,
[Q_KEY_CODE_2] = KEY_2, [Q_KEY_CODE_2] = KEY_2,
@ -138,20 +138,20 @@ static const unsigned int keymap_qcode[Q_KEY_CODE_MAX] = {
[Q_KEY_CODE_MENU] = KEY_MENU, [Q_KEY_CODE_MENU] = KEY_MENU,
}; };
static const unsigned int keymap_button[INPUT_BUTTON_MAX] = { static const unsigned int keymap_button[INPUT_BUTTON__MAX] = {
[INPUT_BUTTON_LEFT] = BTN_LEFT, [INPUT_BUTTON_LEFT] = BTN_LEFT,
[INPUT_BUTTON_RIGHT] = BTN_RIGHT, [INPUT_BUTTON_RIGHT] = BTN_RIGHT,
[INPUT_BUTTON_MIDDLE] = BTN_MIDDLE, [INPUT_BUTTON_MIDDLE] = BTN_MIDDLE,
[INPUT_BUTTON_WHEEL_UP] = BTN_GEAR_UP, [INPUT_BUTTON_WHEELUP] = BTN_GEAR_UP,
[INPUT_BUTTON_WHEEL_DOWN] = BTN_GEAR_DOWN, [INPUT_BUTTON_WHEELDOWN] = BTN_GEAR_DOWN,
}; };
static const unsigned int axismap_rel[INPUT_AXIS_MAX] = { static const unsigned int axismap_rel[INPUT_AXIS__MAX] = {
[INPUT_AXIS_X] = REL_X, [INPUT_AXIS_X] = REL_X,
[INPUT_AXIS_Y] = REL_Y, [INPUT_AXIS_Y] = REL_Y,
}; };
static const unsigned int axismap_abs[INPUT_AXIS_MAX] = { static const unsigned int axismap_abs[INPUT_AXIS__MAX] = {
[INPUT_AXIS_X] = ABS_X, [INPUT_AXIS_X] = ABS_X,
[INPUT_AXIS_Y] = ABS_Y, [INPUT_AXIS_Y] = ABS_Y,
}; };

View File

@ -520,66 +520,6 @@ void bdrv_op_block_all(BlockDriverState *bs, Error *reason);
void bdrv_op_unblock_all(BlockDriverState *bs, Error *reason); void bdrv_op_unblock_all(BlockDriverState *bs, Error *reason);
bool bdrv_op_blocker_is_empty(BlockDriverState *bs); bool bdrv_op_blocker_is_empty(BlockDriverState *bs);
typedef enum {
BLKDBG_L1_UPDATE,
BLKDBG_L1_GROW_ALLOC_TABLE,
BLKDBG_L1_GROW_WRITE_TABLE,
BLKDBG_L1_GROW_ACTIVATE_TABLE,
BLKDBG_L2_LOAD,
BLKDBG_L2_UPDATE,
BLKDBG_L2_UPDATE_COMPRESSED,
BLKDBG_L2_ALLOC_COW_READ,
BLKDBG_L2_ALLOC_WRITE,
BLKDBG_READ_AIO,
BLKDBG_READ_BACKING_AIO,
BLKDBG_READ_COMPRESSED,
BLKDBG_WRITE_AIO,
BLKDBG_WRITE_COMPRESSED,
BLKDBG_VMSTATE_LOAD,
BLKDBG_VMSTATE_SAVE,
BLKDBG_COW_READ,
BLKDBG_COW_WRITE,
BLKDBG_REFTABLE_LOAD,
BLKDBG_REFTABLE_GROW,
BLKDBG_REFTABLE_UPDATE,
BLKDBG_REFBLOCK_LOAD,
BLKDBG_REFBLOCK_UPDATE,
BLKDBG_REFBLOCK_UPDATE_PART,
BLKDBG_REFBLOCK_ALLOC,
BLKDBG_REFBLOCK_ALLOC_HOOKUP,
BLKDBG_REFBLOCK_ALLOC_WRITE,
BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS,
BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE,
BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE,
BLKDBG_CLUSTER_ALLOC,
BLKDBG_CLUSTER_ALLOC_BYTES,
BLKDBG_CLUSTER_FREE,
BLKDBG_FLUSH_TO_OS,
BLKDBG_FLUSH_TO_DISK,
BLKDBG_PWRITEV_RMW_HEAD,
BLKDBG_PWRITEV_RMW_AFTER_HEAD,
BLKDBG_PWRITEV_RMW_TAIL,
BLKDBG_PWRITEV_RMW_AFTER_TAIL,
BLKDBG_PWRITEV,
BLKDBG_PWRITEV_ZERO,
BLKDBG_PWRITEV_DONE,
BLKDBG_EMPTY_IMAGE_PREPARE,
BLKDBG_EVENT_MAX,
} BlkDebugEvent;
#define BLKDBG_EVENT(child, evt) \ #define BLKDBG_EVENT(child, evt) \
do { \ do { \
if (child) { \ if (child) { \
@ -587,7 +527,7 @@ typedef enum {
} \ } \
} while (0) } while (0)
void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event); void bdrv_debug_event(BlockDriverState *bs, BlkdebugEvent event);
int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event, int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event,
const char *tag); const char *tag);

View File

@ -244,7 +244,7 @@ struct BlockDriver {
int (*bdrv_amend_options)(BlockDriverState *bs, QemuOpts *opts, int (*bdrv_amend_options)(BlockDriverState *bs, QemuOpts *opts,
BlockDriverAmendStatusCB *status_cb); BlockDriverAmendStatusCB *status_cb);
void (*bdrv_debug_event)(BlockDriverState *bs, BlkDebugEvent event); void (*bdrv_debug_event)(BlockDriverState *bs, BlkdebugEvent event);
/* TODO Better pass a option string/QDict/QemuOpts to add any rule? */ /* TODO Better pass a option string/QDict/QemuOpts to add any rule? */
int (*bdrv_debug_breakpoint)(BlockDriverState *bs, const char *event, int (*bdrv_debug_breakpoint)(BlockDriverState *bs, const char *event,

View File

@ -239,7 +239,7 @@ struct Property {
PropertyInfo *info; PropertyInfo *info;
ptrdiff_t offset; ptrdiff_t offset;
uint8_t bitnr; uint8_t bitnr;
qtype_code qtype; QType qtype;
int64_t defval; int64_t defval;
int arrayoffset; int arrayoffset;
PropertyInfo *arrayinfo; PropertyInfo *arrayinfo;

View File

@ -133,7 +133,7 @@ struct MigrationState
QemuThread thread; QemuThread thread;
QEMUBH *cleanup_bh; QEMUBH *cleanup_bh;
QEMUFile *file; QEMUFile *file;
int parameters[MIGRATION_PARAMETER_MAX]; int parameters[MIGRATION_PARAMETER__MAX];
int state; int state;
MigrationParams params; MigrationParams params;
@ -151,7 +151,7 @@ struct MigrationState
int64_t expected_downtime; int64_t expected_downtime;
int64_t dirty_pages_rate; int64_t dirty_pages_rate;
int64_t dirty_bytes_rate; int64_t dirty_bytes_rate;
bool enabled_capabilities[MIGRATION_CAPABILITY_MAX]; bool enabled_capabilities[MIGRATION_CAPABILITY__MAX];
int64_t xbzrle_cache_size; int64_t xbzrle_cache_size;
int64_t setup_time; int64_t setup_time;
int64_t dirty_sync_count; int64_t dirty_sync_count;

View File

@ -90,6 +90,20 @@
*/ */
typedef struct Error Error; typedef struct Error Error;
/*
* Overall category of an error.
* Based on the qapi type QapiErrorClass, but reproduced here for nicer
* enum names.
*/
typedef enum ErrorClass {
ERROR_CLASS_GENERIC_ERROR = QAPI_ERROR_CLASS_GENERICERROR,
ERROR_CLASS_COMMAND_NOT_FOUND = QAPI_ERROR_CLASS_COMMANDNOTFOUND,
ERROR_CLASS_DEVICE_ENCRYPTED = QAPI_ERROR_CLASS_DEVICEENCRYPTED,
ERROR_CLASS_DEVICE_NOT_ACTIVE = QAPI_ERROR_CLASS_DEVICENOTACTIVE,
ERROR_CLASS_DEVICE_NOT_FOUND = QAPI_ERROR_CLASS_DEVICENOTFOUND,
ERROR_CLASS_KVM_MISSING_CAP = QAPI_ERROR_CLASS_KVMMISSINGCAP,
} ErrorClass;
/* /*
* Get @err's human-readable error message. * Get @err's human-readable error message.
*/ */

View File

@ -25,5 +25,6 @@ typedef struct QBool {
QBool *qbool_from_bool(bool value); QBool *qbool_from_bool(bool value);
bool qbool_get_bool(const QBool *qb); bool qbool_get_bool(const QBool *qb);
QBool *qobject_to_qbool(const QObject *obj); QBool *qobject_to_qbool(const QObject *obj);
void qbool_destroy_obj(QObject *obj);
#endif /* QBOOL_H */ #endif /* QBOOL_H */

View File

@ -48,6 +48,7 @@ void qdict_iter(const QDict *qdict,
void *opaque); void *opaque);
const QDictEntry *qdict_first(const QDict *qdict); const QDictEntry *qdict_first(const QDict *qdict);
const QDictEntry *qdict_next(const QDict *qdict, const QDictEntry *entry); const QDictEntry *qdict_next(const QDict *qdict, const QDictEntry *entry);
void qdict_destroy_obj(QObject *obj);
/* Helper to qdict_put_obj(), accepts any object */ /* Helper to qdict_put_obj(), accepts any object */
#define qdict_put(qdict, key, obj) \ #define qdict_put(qdict, key, obj) \

View File

@ -25,5 +25,6 @@ typedef struct QFloat {
QFloat *qfloat_from_double(double value); QFloat *qfloat_from_double(double value);
double qfloat_get_double(const QFloat *qi); double qfloat_get_double(const QFloat *qi);
QFloat *qobject_to_qfloat(const QObject *obj); QFloat *qobject_to_qfloat(const QObject *obj);
void qfloat_destroy_obj(QObject *obj);
#endif /* QFLOAT_H */ #endif /* QFLOAT_H */

View File

@ -24,5 +24,6 @@ typedef struct QInt {
QInt *qint_from_int(int64_t value); QInt *qint_from_int(int64_t value);
int64_t qint_get_int(const QInt *qi); int64_t qint_get_int(const QInt *qi);
QInt *qobject_to_qint(const QObject *obj); QInt *qobject_to_qint(const QObject *obj);
void qint_destroy_obj(QObject *obj);
#endif /* QINT_H */ #endif /* QINT_H */

View File

@ -49,6 +49,7 @@ QObject *qlist_peek(QList *qlist);
int qlist_empty(const QList *qlist); int qlist_empty(const QList *qlist);
size_t qlist_size(const QList *qlist); size_t qlist_size(const QList *qlist);
QList *qobject_to_qlist(const QObject *obj); QList *qobject_to_qlist(const QObject *obj);
void qlist_destroy_obj(QObject *obj);
static inline const QListEntry *qlist_first(const QList *qlist) static inline const QListEntry *qlist_first(const QList *qlist)
{ {

View File

@ -34,30 +34,12 @@
#include <stddef.h> #include <stddef.h>
#include <assert.h> #include <assert.h>
#include "qapi-types.h"
typedef enum { struct QObject {
QTYPE_NONE, /* sentinel value, no QObject has this type code */ QType type;
QTYPE_QNULL,
QTYPE_QINT,
QTYPE_QSTRING,
QTYPE_QDICT,
QTYPE_QLIST,
QTYPE_QFLOAT,
QTYPE_QBOOL,
QTYPE_MAX,
} qtype_code;
struct QObject;
typedef struct QType {
qtype_code code;
void (*destroy)(struct QObject *);
} QType;
typedef struct QObject {
const QType *type;
size_t refcnt; size_t refcnt;
} QObject; };
/* Get the 'base' part of an object */ /* Get the 'base' part of an object */
#define QOBJECT(obj) (&(obj)->base) #define QOBJECT(obj) (&(obj)->base)
@ -71,9 +53,12 @@ typedef struct QObject {
qobject_decref(obj ? QOBJECT(obj) : NULL) qobject_decref(obj ? QOBJECT(obj) : NULL)
/* Initialize an object to default values */ /* Initialize an object to default values */
#define QOBJECT_INIT(obj, qtype_type) \ static inline void qobject_init(QObject *obj, QType type)
obj->base.refcnt = 1; \ {
obj->base.type = qtype_type assert(QTYPE_NONE < type && type < QTYPE__MAX);
obj->refcnt = 1;
obj->type = type;
}
/** /**
* qobject_incref(): Increment QObject's reference count * qobject_incref(): Increment QObject's reference count
@ -84,6 +69,11 @@ static inline void qobject_incref(QObject *obj)
obj->refcnt++; obj->refcnt++;
} }
/**
* qobject_destroy(): Free resources used by the object
*/
void qobject_destroy(QObject *obj);
/** /**
* qobject_decref(): Decrement QObject's reference count, deallocate * qobject_decref(): Decrement QObject's reference count, deallocate
* when it reaches zero * when it reaches zero
@ -92,19 +82,17 @@ static inline void qobject_decref(QObject *obj)
{ {
assert(!obj || obj->refcnt); assert(!obj || obj->refcnt);
if (obj && --obj->refcnt == 0) { if (obj && --obj->refcnt == 0) {
assert(obj->type != NULL); qobject_destroy(obj);
assert(obj->type->destroy != NULL);
obj->type->destroy(obj);
} }
} }
/** /**
* qobject_type(): Return the QObject's type * qobject_type(): Return the QObject's type
*/ */
static inline qtype_code qobject_type(const QObject *obj) static inline QType qobject_type(const QObject *obj)
{ {
assert(obj->type != NULL); assert(QTYPE_NONE < obj->type && obj->type < QTYPE__MAX);
return obj->type->code; return obj->type;
} }
extern QObject qnull_; extern QObject qnull_;

View File

@ -32,5 +32,6 @@ void qstring_append_int(QString *qstring, int64_t value);
void qstring_append(QString *qstring, const char *str); void qstring_append(QString *qstring, const char *str);
void qstring_append_chr(QString *qstring, int c); void qstring_append_chr(QString *qstring, int c);
QString *qobject_to_qstring(const QObject *obj); QString *qobject_to_qstring(const QObject *obj);
void qstring_destroy_obj(QObject *obj);
#endif /* QSTRING_H */ #endif /* QSTRING_H */

View File

@ -32,7 +32,8 @@ struct Visitor
void (*type_enum)(Visitor *v, int *obj, const char * const strings[], void (*type_enum)(Visitor *v, int *obj, const char * const strings[],
const char *kind, const char *name, Error **errp); const char *kind, const char *name, Error **errp);
void (*get_next_type)(Visitor *v, int *kind, const int *qobjects, /* May be NULL; only needed for input visitors. */
void (*get_next_type)(Visitor *v, QType *type, bool promote_int,
const char *name, Error **errp); const char *name, Error **errp);
void (*type_int)(Visitor *v, int64_t *obj, const char *name, Error **errp); void (*type_int)(Visitor *v, int64_t *obj, const char *name, Error **errp);
@ -43,9 +44,8 @@ struct Visitor
void (*type_any)(Visitor *v, QObject **obj, const char *name, void (*type_any)(Visitor *v, QObject **obj, const char *name,
Error **errp); Error **errp);
/* May be NULL */ /* May be NULL; most useful for input visitors. */
void (*optional)(Visitor *v, bool *present, const char *name, void (*optional)(Visitor *v, bool *present, const char *name);
Error **errp);
void (*type_uint8)(Visitor *v, uint8_t *obj, const char *name, Error **errp); void (*type_uint8)(Visitor *v, uint8_t *obj, const char *name, Error **errp);
void (*type_uint16)(Visitor *v, uint16_t *obj, const char *name, Error **errp); void (*type_uint16)(Visitor *v, uint16_t *obj, const char *name, Error **errp);

View File

@ -27,9 +27,6 @@ typedef struct GenericList
struct GenericList *next; struct GenericList *next;
} GenericList; } GenericList;
void visit_start_handle(Visitor *v, void **obj, const char *kind,
const char *name, Error **errp);
void visit_end_handle(Visitor *v, Error **errp);
void visit_start_struct(Visitor *v, void **obj, const char *kind, void visit_start_struct(Visitor *v, void **obj, const char *kind,
const char *name, size_t size, Error **errp); const char *name, size_t size, Error **errp);
void visit_end_struct(Visitor *v, Error **errp); void visit_end_struct(Visitor *v, Error **errp);
@ -39,9 +36,22 @@ void visit_end_implicit_struct(Visitor *v, Error **errp);
void visit_start_list(Visitor *v, const char *name, Error **errp); void visit_start_list(Visitor *v, const char *name, Error **errp);
GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp); GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp);
void visit_end_list(Visitor *v, Error **errp); void visit_end_list(Visitor *v, Error **errp);
void visit_optional(Visitor *v, bool *present, const char *name,
Error **errp); /**
void visit_get_next_type(Visitor *v, int *obj, const int *qtypes, * Check if an optional member @name of an object needs visiting.
* For input visitors, set *@present according to whether the
* corresponding visit_type_*() needs calling; for other visitors,
* leave *@present unchanged. Return *@present for convenience.
*/
bool visit_optional(Visitor *v, bool *present, const char *name);
/**
* Determine the qtype of the item @name in the current object visit.
* For input visitors, set *@type to the correct qtype of a qapi
* alternate type; for other visitors, leave *@type unchanged.
* If @promote_int, treat integers as QTYPE_FLOAT.
*/
void visit_get_next_type(Visitor *v, QType *type, bool promote_int,
const char *name, Error **errp); const char *name, Error **errp);
void visit_type_enum(Visitor *v, int *obj, const char * const strings[], void visit_type_enum(Visitor *v, int *obj, const char * const strings[],
const char *kind, const char *name, Error **errp); const char *kind, const char *name, Error **errp);

View File

@ -80,6 +80,7 @@ typedef struct QEMUSGList QEMUSGList;
typedef struct QEMUSizedBuffer QEMUSizedBuffer; typedef struct QEMUSizedBuffer QEMUSizedBuffer;
typedef struct QEMUTimer QEMUTimer; typedef struct QEMUTimer QEMUTimer;
typedef struct QEMUTimerListGroup QEMUTimerListGroup; typedef struct QEMUTimerListGroup QEMUTimerListGroup;
typedef struct QObject QObject;
typedef struct RAMBlock RAMBlock; typedef struct RAMBlock RAMBlock;
typedef struct Range Range; typedef struct Range Range;
typedef struct SerialState SerialState; typedef struct SerialState SerialState;

View File

@ -202,7 +202,7 @@ static int global_state_post_load(void *opaque, int version_id)
s->received = true; s->received = true;
trace_migrate_global_state_post_load(runstate); trace_migrate_global_state_post_load(runstate);
r = qapi_enum_parse(RunState_lookup, runstate, RUN_STATE_MAX, r = qapi_enum_parse(RunState_lookup, runstate, RUN_STATE__MAX,
-1, &local_err); -1, &local_err);
if (r == -1) { if (r == -1) {
@ -479,7 +479,7 @@ MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp)
int i; int i;
caps = NULL; /* silence compiler warning */ caps = NULL; /* silence compiler warning */
for (i = 0; i < MIGRATION_CAPABILITY_MAX; i++) { for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
if (head == NULL) { if (head == NULL) {
head = g_malloc0(sizeof(*caps)); head = g_malloc0(sizeof(*caps));
caps = head; caps = head;

View File

@ -403,7 +403,7 @@ static QDict *build_qmp_error_dict(Error *err)
QObject *obj; QObject *obj;
obj = qobject_from_jsonf("{ 'error': { 'class': %s, 'desc': %s } }", obj = qobject_from_jsonf("{ 'error': { 'class': %s, 'desc': %s } }",
ErrorClass_lookup[error_get_class(err)], QapiErrorClass_lookup[error_get_class(err)],
error_get_pretty(err)); error_get_pretty(err));
return qobject_to_qdict(obj); return qobject_to_qdict(obj);
@ -441,7 +441,7 @@ static void monitor_protocol_emitter(Monitor *mon, QObject *data,
} }
static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT_MAX] = { static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = {
/* Limit guest-triggerable events to 1 per second */ /* Limit guest-triggerable events to 1 per second */
[QAPI_EVENT_RTC_CHANGE] = { 1000 * SCALE_MS }, [QAPI_EVENT_RTC_CHANGE] = { 1000 * SCALE_MS },
[QAPI_EVENT_WATCHDOG] = { 1000 * SCALE_MS }, [QAPI_EVENT_WATCHDOG] = { 1000 * SCALE_MS },
@ -481,7 +481,7 @@ monitor_qapi_event_queue(QAPIEvent event, QDict *qdict, Error **errp)
MonitorQAPIEventConf *evconf; MonitorQAPIEventConf *evconf;
MonitorQAPIEventState *evstate; MonitorQAPIEventState *evstate;
assert(event < QAPI_EVENT_MAX); assert(event < QAPI_EVENT__MAX);
evconf = &monitor_qapi_event_conf[event]; evconf = &monitor_qapi_event_conf[event];
trace_monitor_protocol_event_queue(event, qdict, evconf->rate); trace_monitor_protocol_event_queue(event, qdict, evconf->rate);
@ -946,7 +946,7 @@ EventInfoList *qmp_query_events(Error **errp)
EventInfoList *info, *ev_list = NULL; EventInfoList *info, *ev_list = NULL;
QAPIEvent e; QAPIEvent e;
for (e = 0 ; e < QAPI_EVENT_MAX ; e++) { for (e = 0 ; e < QAPI_EVENT__MAX ; e++) {
const char *event_name = QAPIEvent_lookup[e]; const char *event_name = QAPIEvent_lookup[e];
assert(event_name != NULL); assert(event_name != NULL);
info = g_malloc0(sizeof(*info)); info = g_malloc0(sizeof(*info));
@ -1375,7 +1375,7 @@ static void hmp_mouse_move(Monitor *mon, const QDict *qdict)
if (dz_str) { if (dz_str) {
dz = strtol(dz_str, NULL, 0); dz = strtol(dz_str, NULL, 0);
if (dz != 0) { if (dz != 0) {
button = (dz > 0) ? INPUT_BUTTON_WHEEL_UP : INPUT_BUTTON_WHEEL_DOWN; button = (dz > 0) ? INPUT_BUTTON_WHEELUP : INPUT_BUTTON_WHEELDOWN;
qemu_input_queue_btn(NULL, button, true); qemu_input_queue_btn(NULL, button, true);
qemu_input_event_sync(); qemu_input_event_sync();
qemu_input_queue_btn(NULL, button, false); qemu_input_queue_btn(NULL, button, false);
@ -1386,7 +1386,7 @@ static void hmp_mouse_move(Monitor *mon, const QDict *qdict)
static void hmp_mouse_button(Monitor *mon, const QDict *qdict) static void hmp_mouse_button(Monitor *mon, const QDict *qdict)
{ {
static uint32_t bmap[INPUT_BUTTON_MAX] = { static uint32_t bmap[INPUT_BUTTON__MAX] = {
[INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON, [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
[INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON, [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
[INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON, [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
@ -3217,7 +3217,7 @@ void sendkey_completion(ReadLineState *rs, int nb_args, const char *str)
} }
len = strlen(str); len = strlen(str);
readline_set_completion_index(rs, len); readline_set_completion_index(rs, len);
for (i = 0; i < Q_KEY_CODE_MAX; i++) { for (i = 0; i < Q_KEY_CODE__MAX; i++) {
if (!strncmp(str, QKeyCode_lookup[i], len)) { if (!strncmp(str, QKeyCode_lookup[i], len)) {
readline_add_completion(rs, QKeyCode_lookup[i]); readline_add_completion(rs, QKeyCode_lookup[i]);
} }
@ -3316,7 +3316,7 @@ void migrate_set_capability_completion(ReadLineState *rs, int nb_args,
readline_set_completion_index(rs, len); readline_set_completion_index(rs, len);
if (nb_args == 2) { if (nb_args == 2) {
int i; int i;
for (i = 0; i < MIGRATION_CAPABILITY_MAX; i++) { for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
const char *name = MigrationCapability_lookup[i]; const char *name = MigrationCapability_lookup[i];
if (!strncmp(str, name, len)) { if (!strncmp(str, name, len)) {
readline_add_completion(rs, name); readline_add_completion(rs, name);
@ -3337,7 +3337,7 @@ void migrate_set_parameter_completion(ReadLineState *rs, int nb_args,
readline_set_completion_index(rs, len); readline_set_completion_index(rs, len);
if (nb_args == 2) { if (nb_args == 2) {
int i; int i;
for (i = 0; i < MIGRATION_PARAMETER_MAX; i++) { for (i = 0; i < MIGRATION_PARAMETER__MAX; i++) {
const char *name = MigrationParameter_lookup[i]; const char *name = MigrationParameter_lookup[i];
if (!strncmp(str, name, len)) { if (!strncmp(str, name, len)) {
readline_add_completion(rs, name); readline_add_completion(rs, name);

View File

@ -943,7 +943,7 @@ static int net_init_nic(const NetClientOptions *opts, const char *name,
} }
static int (* const net_client_init_fun[NET_CLIENT_OPTIONS_KIND_MAX])( static int (* const net_client_init_fun[NET_CLIENT_OPTIONS_KIND__MAX])(
const NetClientOptions *opts, const NetClientOptions *opts,
const char *name, const char *name,
NetClientState *peer, Error **errp) = { NetClientState *peer, Error **errp) = {
@ -1296,7 +1296,7 @@ void qmp_set_link(const char *name, bool up, Error **errp)
int queues, i; int queues, i;
queues = qemu_find_net_clients_except(name, ncs, queues = qemu_find_net_clients_except(name, ncs,
NET_CLIENT_OPTIONS_KIND_MAX, NET_CLIENT_OPTIONS_KIND__MAX,
MAX_QUEUE_NUM); MAX_QUEUE_NUM);
if (queues == 0) { if (queues == 0) {

View File

@ -744,43 +744,125 @@
{ 'command': 'query-mice', 'returns': ['MouseInfo'] } { 'command': 'query-mice', 'returns': ['MouseInfo'] }
## ##
# @CpuInfo: # @CpuInfoArch:
# #
# Information about a virtual CPU # An enumeration of cpu types that enable additional information during
# @query-cpus.
#
# Since: 2.6
##
{ 'enum': 'CpuInfoArch',
'data': ['x86', 'sparc', 'ppc', 'mips', 'tricore', 'other' ] }
##
# @CpuInfoBase:
#
# Common information about a virtual CPU
# #
# @CPU: the index of the virtual CPU # @CPU: the index of the virtual CPU
# #
# @current: this only exists for backwards compatible and should be ignored # @current: this only exists for backwards compatibility and should be ignored
# #
# @halted: true if the virtual CPU is in the halt state. Halt usually refers # @halted: true if the virtual CPU is in the halt state. Halt usually refers
# to a processor specific low power mode. # to a processor specific low power mode.
# #
# @qom_path: path to the CPU object in the QOM tree (since 2.4) # @qom_path: path to the CPU object in the QOM tree (since 2.4)
# #
# @pc: #optional If the target is i386 or x86_64, this is the 64-bit instruction
# pointer.
# If the target is Sparc, this is the PC component of the
# instruction pointer.
#
# @nip: #optional If the target is PPC, the instruction pointer
#
# @npc: #optional If the target is Sparc, the NPC component of the instruction
# pointer
#
# @PC: #optional If the target is MIPS, the instruction pointer
#
# @thread_id: ID of the underlying host thread # @thread_id: ID of the underlying host thread
# #
# @arch: architecture of the cpu, which determines which additional fields
# will be listed (since 2.6)
#
# Since: 0.14.0 # Since: 0.14.0
# #
# Notes: @halted is a transient state that changes frequently. By the time the # Notes: @halted is a transient state that changes frequently. By the time the
# data is sent to the client, the guest may no longer be halted. # data is sent to the client, the guest may no longer be halted.
## ##
{ 'struct': 'CpuInfo', { 'struct': 'CpuInfoBase',
'data': {'CPU': 'int', 'current': 'bool', 'halted': 'bool', 'data': {'CPU': 'int', 'current': 'bool', 'halted': 'bool',
'qom_path': 'str', 'qom_path': 'str', 'thread_id': 'int', 'arch': 'CpuInfoArch' } }
'*pc': 'int', '*nip': 'int', '*npc': 'int', '*PC': 'int',
'thread_id': 'int'} } ##
# @CpuInfo:
#
# Information about a virtual CPU
#
# Since: 0.14.0
##
{ 'union': 'CpuInfo', 'base': 'CpuInfoBase', 'discriminator': 'arch',
'data': { 'x86': 'CpuInfoX86',
'sparc': 'CpuInfoSPARC',
'ppc': 'CpuInfoPPC',
'mips': 'CpuInfoMIPS',
'tricore': 'CpuInfoTricore',
'other': 'CpuInfoOther' } }
##
# @CpuInfoX86:
#
# Additional information about a virtual i386 or x86_64 CPU
#
# @pc: the 64-bit instruction pointer
#
# Since 2.6
##
{ 'struct': 'CpuInfoX86', 'data': { 'pc': 'int' } }
##
# @CpuInfoSPARC:
#
# Additional information about a virtual SPARC CPU
#
# @pc: the PC component of the instruction pointer
#
# @npc: the NPC component of the instruction pointer
#
# Since 2.6
##
{ 'struct': 'CpuInfoSPARC', 'data': { 'pc': 'int', 'npc': 'int' } }
##
# @CpuInfoPPC:
#
# Additional information about a virtual PPC CPU
#
# @nip: the instruction pointer
#
# Since 2.6
##
{ 'struct': 'CpuInfoPPC', 'data': { 'nip': 'int' } }
##
# @CpuInfoMIPS:
#
# Additional information about a virtual MIPS CPU
#
# @PC: the instruction pointer
#
# Since 2.6
##
{ 'struct': 'CpuInfoMIPS', 'data': { 'PC': 'int' } }
##
# @CpuInfoTricore:
#
# Additional information about a virtual Tricore CPU
#
# @PC: the instruction pointer
#
# Since 2.6
##
{ 'struct': 'CpuInfoTricore', 'data': { 'PC': 'int' } }
##
# @CpuInfoOther:
#
# No additional information is available about the virtual CPU
#
# Since 2.6
#
##
{ 'struct': 'CpuInfoOther', 'data': { } }
## ##
# @query-cpus: # @query-cpus:

View File

@ -1776,21 +1776,23 @@
# @BlkdebugEvent # @BlkdebugEvent
# #
# Trigger events supported by blkdebug. # Trigger events supported by blkdebug.
#
# Since: 2.0
## ##
{ 'enum': 'BlkdebugEvent', { 'enum': 'BlkdebugEvent', 'prefix': 'BLKDBG',
'data': [ 'l1_update', 'l1_grow.alloc_table', 'l1_grow.write_table', 'data': [ 'l1_update', 'l1_grow_alloc_table', 'l1_grow_write_table',
'l1_grow.activate_table', 'l2_load', 'l2_update', 'l1_grow_activate_table', 'l2_load', 'l2_update',
'l2_update_compressed', 'l2_alloc.cow_read', 'l2_alloc.write', 'l2_update_compressed', 'l2_alloc_cow_read', 'l2_alloc_write',
'read_aio', 'read_backing_aio', 'read_compressed', 'write_aio', 'read_aio', 'read_backing_aio', 'read_compressed', 'write_aio',
'write_compressed', 'vmstate_load', 'vmstate_save', 'cow_read', 'write_compressed', 'vmstate_load', 'vmstate_save', 'cow_read',
'cow_write', 'reftable_load', 'reftable_grow', 'reftable_update', 'cow_write', 'reftable_load', 'reftable_grow', 'reftable_update',
'refblock_load', 'refblock_update', 'refblock_update_part', 'refblock_load', 'refblock_update', 'refblock_update_part',
'refblock_alloc', 'refblock_alloc.hookup', 'refblock_alloc.write', 'refblock_alloc', 'refblock_alloc_hookup', 'refblock_alloc_write',
'refblock_alloc.write_blocks', 'refblock_alloc.write_table', 'refblock_alloc_write_blocks', 'refblock_alloc_write_table',
'refblock_alloc.switch_table', 'cluster_alloc', 'refblock_alloc_switch_table', 'cluster_alloc',
'cluster_alloc_bytes', 'cluster_free', 'flush_to_os', 'cluster_alloc_bytes', 'cluster_free', 'flush_to_os',
'flush_to_disk', 'pwritev_rmw.head', 'pwritev_rmw.after_head', 'flush_to_disk', 'pwritev_rmw_head', 'pwritev_rmw_after_head',
'pwritev_rmw.tail', 'pwritev_rmw.after_tail', 'pwritev', 'pwritev_rmw_tail', 'pwritev_rmw_after_tail', 'pwritev',
'pwritev_zero', 'pwritev_done', 'empty_image_prepare' ] } 'pwritev_zero', 'pwritev_done', 'empty_image_prepare' ] }
## ##

View File

@ -3,7 +3,7 @@
# QAPI common definitions # QAPI common definitions
## ##
# @ErrorClass # @QapiErrorClass
# #
# QEMU error classes # QEMU error classes
# #
@ -24,7 +24,8 @@
# #
# Since: 1.2 # Since: 1.2
## ##
{ 'enum': 'ErrorClass', { 'enum': 'QapiErrorClass',
# Keep this in sync with ErrorClass in error.h
'data': [ 'GenericError', 'CommandNotFound', 'DeviceEncrypted', 'data': [ 'GenericError', 'CommandNotFound', 'DeviceEncrypted',
'DeviceNotActive', 'DeviceNotFound', 'KVMMissingCap' ] } 'DeviceNotActive', 'DeviceNotFound', 'KVMMissingCap' ] }

View File

@ -488,7 +488,7 @@ opts_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp)
static void static void
opts_optional(Visitor *v, bool *present, const char *name, Error **errp) opts_optional(Visitor *v, bool *present, const char *name)
{ {
OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v);

View File

@ -73,19 +73,19 @@ void visit_end_union(Visitor *v, bool data_present, Error **errp)
} }
} }
void visit_optional(Visitor *v, bool *present, const char *name, bool visit_optional(Visitor *v, bool *present, const char *name)
Error **errp)
{ {
if (v->optional) { if (v->optional) {
v->optional(v, present, name, errp); v->optional(v, present, name);
} }
return *present;
} }
void visit_get_next_type(Visitor *v, int *obj, const int *qtypes, void visit_get_next_type(Visitor *v, QType *type, bool promote_int,
const char *name, Error **errp) const char *name, Error **errp)
{ {
if (v->get_next_type) { if (v->get_next_type) {
v->get_next_type(v, obj, qtypes, name, errp); v->get_next_type(v, type, promote_int, name, errp);
} }
} }

View File

@ -114,7 +114,7 @@ static QObject *do_qmp_dispatch(QObject *request, Error **errp)
QObject *qmp_build_error_object(Error *err) QObject *qmp_build_error_object(Error *err)
{ {
return qobject_from_jsonf("{ 'class': %s, 'desc': %s }", return qobject_from_jsonf("{ 'class': %s, 'desc': %s }",
ErrorClass_lookup[error_get_class(err)], QapiErrorClass_lookup[error_get_class(err)],
error_get_pretty(err)); error_get_pretty(err));
} }

View File

@ -208,7 +208,7 @@ static void qmp_input_end_list(Visitor *v, Error **errp)
qmp_input_pop(qiv, errp); qmp_input_pop(qiv, errp);
} }
static void qmp_input_get_next_type(Visitor *v, int *kind, const int *qobjects, static void qmp_input_get_next_type(Visitor *v, QType *type, bool promote_int,
const char *name, Error **errp) const char *name, Error **errp)
{ {
QmpInputVisitor *qiv = to_qiv(v); QmpInputVisitor *qiv = to_qiv(v);
@ -218,7 +218,10 @@ static void qmp_input_get_next_type(Visitor *v, int *kind, const int *qobjects,
error_setg(errp, QERR_MISSING_PARAMETER, name ? name : "null"); error_setg(errp, QERR_MISSING_PARAMETER, name ? name : "null");
return; return;
} }
*kind = qobjects[qobject_type(qobj)]; *type = qobject_type(qobj);
if (promote_int && *type == QTYPE_QINT) {
*type = QTYPE_QFLOAT;
}
} }
static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name, static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name,
@ -300,8 +303,7 @@ static void qmp_input_type_any(Visitor *v, QObject **obj, const char *name,
*obj = qobj; *obj = qobj;
} }
static void qmp_input_optional(Visitor *v, bool *present, const char *name, static void qmp_input_optional(Visitor *v, bool *present, const char *name)
Error **errp)
{ {
QmpInputVisitor *qiv = to_qiv(v); QmpInputVisitor *qiv = to_qiv(v);
QObject *qobj = qmp_input_get_object(qiv, name, true); QObject *qobj = qmp_input_get_object(qiv, name, true);

View File

@ -299,8 +299,7 @@ static void parse_type_number(Visitor *v, double *obj, const char *name,
*obj = val; *obj = val;
} }
static void parse_optional(Visitor *v, bool *present, const char *name, static void parse_optional(Visitor *v, bool *present, const char *name)
Error **errp)
{ {
StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v); StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);

View File

@ -487,7 +487,7 @@ int main(int argc, char **argv)
detect_zeroes = detect_zeroes =
qapi_enum_parse(BlockdevDetectZeroesOptions_lookup, qapi_enum_parse(BlockdevDetectZeroesOptions_lookup,
optarg, optarg,
BLOCKDEV_DETECT_ZEROES_OPTIONS_MAX, BLOCKDEV_DETECT_ZEROES_OPTIONS__MAX,
BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF, BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
&local_err); &local_err);
if (local_err) { if (local_err) {

View File

@ -2765,6 +2765,8 @@ Return a json-array. Each CPU is represented by a json-object, which contains:
- "current": true if this is the current CPU, false otherwise (json-bool) - "current": true if this is the current CPU, false otherwise (json-bool)
- "halted": true if the cpu is halted, false otherwise (json-bool) - "halted": true if the cpu is halted, false otherwise (json-bool)
- "qom_path": path to the CPU object in the QOM tree (json-str) - "qom_path": path to the CPU object in the QOM tree (json-str)
- "arch": architecture of the cpu, which determines what additional
keys will be present (json-str)
- Current program counter. The key's name depends on the architecture: - Current program counter. The key's name depends on the architecture:
"pc": i386/x86_64 (json-int) "pc": i386/x86_64 (json-int)
"nip": PPC (json-int) "nip": PPC (json-int)
@ -2782,6 +2784,7 @@ Example:
"current":true, "current":true,
"halted":false, "halted":false,
"qom_path":"/machine/unattached/device[0]", "qom_path":"/machine/unattached/device[0]",
"arch":"x86",
"pc":3227107138, "pc":3227107138,
"thread_id":3134 "thread_id":3134
}, },
@ -2790,6 +2793,7 @@ Example:
"current":false, "current":false,
"halted":true, "halted":true,
"qom_path":"/machine/unattached/device[2]", "qom_path":"/machine/unattached/device[2]",
"arch":"x86",
"pc":7108165, "pc":7108165,
"thread_id":3135 "thread_id":3135
} }

View File

@ -1,2 +1,2 @@
util-obj-y = qnull.o qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o util-obj-y = qnull.o qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o
util-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o util-obj-y += qjson.o qobject.o json-lexer.o json-streamer.o json-parser.o

View File

@ -15,13 +15,6 @@
#include "qapi/qmp/qobject.h" #include "qapi/qmp/qobject.h"
#include "qemu-common.h" #include "qemu-common.h"
static void qbool_destroy_obj(QObject *obj);
static const QType qbool_type = {
.code = QTYPE_QBOOL,
.destroy = qbool_destroy_obj,
};
/** /**
* qbool_from_bool(): Create a new QBool from a bool * qbool_from_bool(): Create a new QBool from a bool
* *
@ -32,8 +25,8 @@ QBool *qbool_from_bool(bool value)
QBool *qb; QBool *qb;
qb = g_malloc(sizeof(*qb)); qb = g_malloc(sizeof(*qb));
qobject_init(QOBJECT(qb), QTYPE_QBOOL);
qb->value = value; qb->value = value;
QOBJECT_INIT(qb, &qbool_type);
return qb; return qb;
} }
@ -61,7 +54,7 @@ QBool *qobject_to_qbool(const QObject *obj)
* qbool_destroy_obj(): Free all memory allocated by a * qbool_destroy_obj(): Free all memory allocated by a
* QBool object * QBool object
*/ */
static void qbool_destroy_obj(QObject *obj) void qbool_destroy_obj(QObject *obj)
{ {
assert(obj != NULL); assert(obj != NULL);
g_free(qobject_to_qbool(obj)); g_free(qobject_to_qbool(obj));

View File

@ -19,13 +19,6 @@
#include "qemu/queue.h" #include "qemu/queue.h"
#include "qemu-common.h" #include "qemu-common.h"
static void qdict_destroy_obj(QObject *obj);
static const QType qdict_type = {
.code = QTYPE_QDICT,
.destroy = qdict_destroy_obj,
};
/** /**
* qdict_new(): Create a new QDict * qdict_new(): Create a new QDict
* *
@ -36,7 +29,7 @@ QDict *qdict_new(void)
QDict *qdict; QDict *qdict;
qdict = g_malloc0(sizeof(*qdict)); qdict = g_malloc0(sizeof(*qdict));
QOBJECT_INIT(qdict, &qdict_type); qobject_init(QOBJECT(qdict), QTYPE_QDICT);
return qdict; return qdict;
} }
@ -184,8 +177,7 @@ size_t qdict_size(const QDict *qdict)
/** /**
* qdict_get_obj(): Get a QObject of a specific type * qdict_get_obj(): Get a QObject of a specific type
*/ */
static QObject *qdict_get_obj(const QDict *qdict, const char *key, static QObject *qdict_get_obj(const QDict *qdict, const char *key, QType type)
qtype_code type)
{ {
QObject *obj; QObject *obj;
@ -441,7 +433,7 @@ void qdict_del(QDict *qdict, const char *key)
/** /**
* qdict_destroy_obj(): Free all the memory allocated by a QDict * qdict_destroy_obj(): Free all the memory allocated by a QDict
*/ */
static void qdict_destroy_obj(QObject *obj) void qdict_destroy_obj(QObject *obj)
{ {
int i; int i;
QDict *qdict; QDict *qdict;

View File

@ -15,13 +15,6 @@
#include "qapi/qmp/qobject.h" #include "qapi/qmp/qobject.h"
#include "qemu-common.h" #include "qemu-common.h"
static void qfloat_destroy_obj(QObject *obj);
static const QType qfloat_type = {
.code = QTYPE_QFLOAT,
.destroy = qfloat_destroy_obj,
};
/** /**
* qfloat_from_int(): Create a new QFloat from a float * qfloat_from_int(): Create a new QFloat from a float
* *
@ -32,8 +25,8 @@ QFloat *qfloat_from_double(double value)
QFloat *qf; QFloat *qf;
qf = g_malloc(sizeof(*qf)); qf = g_malloc(sizeof(*qf));
qobject_init(QOBJECT(qf), QTYPE_QFLOAT);
qf->value = value; qf->value = value;
QOBJECT_INIT(qf, &qfloat_type);
return qf; return qf;
} }
@ -61,7 +54,7 @@ QFloat *qobject_to_qfloat(const QObject *obj)
* qfloat_destroy_obj(): Free all memory allocated by a * qfloat_destroy_obj(): Free all memory allocated by a
* QFloat object * QFloat object
*/ */
static void qfloat_destroy_obj(QObject *obj) void qfloat_destroy_obj(QObject *obj)
{ {
assert(obj != NULL); assert(obj != NULL);
g_free(qobject_to_qfloat(obj)); g_free(qobject_to_qfloat(obj));

View File

@ -14,13 +14,6 @@
#include "qapi/qmp/qobject.h" #include "qapi/qmp/qobject.h"
#include "qemu-common.h" #include "qemu-common.h"
static void qint_destroy_obj(QObject *obj);
static const QType qint_type = {
.code = QTYPE_QINT,
.destroy = qint_destroy_obj,
};
/** /**
* qint_from_int(): Create a new QInt from an int64_t * qint_from_int(): Create a new QInt from an int64_t
* *
@ -31,8 +24,8 @@ QInt *qint_from_int(int64_t value)
QInt *qi; QInt *qi;
qi = g_malloc(sizeof(*qi)); qi = g_malloc(sizeof(*qi));
qobject_init(QOBJECT(qi), QTYPE_QINT);
qi->value = value; qi->value = value;
QOBJECT_INIT(qi, &qint_type);
return qi; return qi;
} }
@ -60,7 +53,7 @@ QInt *qobject_to_qint(const QObject *obj)
* qint_destroy_obj(): Free all memory allocated by a * qint_destroy_obj(): Free all memory allocated by a
* QInt object * QInt object
*/ */
static void qint_destroy_obj(QObject *obj) void qint_destroy_obj(QObject *obj)
{ {
assert(obj != NULL); assert(obj != NULL);
g_free(qobject_to_qint(obj)); g_free(qobject_to_qint(obj));

View File

@ -15,13 +15,6 @@
#include "qemu/queue.h" #include "qemu/queue.h"
#include "qemu-common.h" #include "qemu-common.h"
static void qlist_destroy_obj(QObject *obj);
static const QType qlist_type = {
.code = QTYPE_QLIST,
.destroy = qlist_destroy_obj,
};
/** /**
* qlist_new(): Create a new QList * qlist_new(): Create a new QList
* *
@ -32,8 +25,8 @@ QList *qlist_new(void)
QList *qlist; QList *qlist;
qlist = g_malloc(sizeof(*qlist)); qlist = g_malloc(sizeof(*qlist));
qobject_init(QOBJECT(qlist), QTYPE_QLIST);
QTAILQ_INIT(&qlist->head); QTAILQ_INIT(&qlist->head);
QOBJECT_INIT(qlist, &qlist_type);
return qlist; return qlist;
} }
@ -151,7 +144,7 @@ QList *qobject_to_qlist(const QObject *obj)
/** /**
* qlist_destroy_obj(): Free all the memory allocated by a QList * qlist_destroy_obj(): Free all the memory allocated by a QList
*/ */
static void qlist_destroy_obj(QObject *obj) void qlist_destroy_obj(QObject *obj)
{ {
QList *qlist; QList *qlist;
QListEntry *entry, *next_entry; QListEntry *entry, *next_entry;

View File

@ -13,17 +13,7 @@
#include "qemu-common.h" #include "qemu-common.h"
#include "qapi/qmp/qobject.h" #include "qapi/qmp/qobject.h"
static void qnull_destroy_obj(QObject *obj)
{
assert(0);
}
static const QType qnull_type = {
.code = QTYPE_QNULL,
.destroy = qnull_destroy_obj,
};
QObject qnull_ = { QObject qnull_ = {
.type = &qnull_type, .type = QTYPE_QNULL,
.refcnt = 1, .refcnt = 1,
}; };

34
qobject/qobject.c Normal file
View File

@ -0,0 +1,34 @@
/*
* QObject
*
* Copyright (C) 2015 Red Hat, Inc.
*
* 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-common.h"
#include "qapi/qmp/qbool.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qfloat.h"
#include "qapi/qmp/qint.h"
#include "qapi/qmp/qlist.h"
#include "qapi/qmp/qstring.h"
static void (*qdestroy[QTYPE__MAX])(QObject *) = {
[QTYPE_NONE] = NULL, /* No such object exists */
[QTYPE_QNULL] = NULL, /* qnull_ is indestructible */
[QTYPE_QINT] = qint_destroy_obj,
[QTYPE_QSTRING] = qstring_destroy_obj,
[QTYPE_QDICT] = qdict_destroy_obj,
[QTYPE_QLIST] = qlist_destroy_obj,
[QTYPE_QFLOAT] = qfloat_destroy_obj,
[QTYPE_QBOOL] = qbool_destroy_obj,
};
void qobject_destroy(QObject *obj)
{
assert(!obj->refcnt);
assert(QTYPE_QNULL < obj->type && obj->type < QTYPE__MAX);
qdestroy[obj->type](obj);
}

View File

@ -14,13 +14,6 @@
#include "qapi/qmp/qstring.h" #include "qapi/qmp/qstring.h"
#include "qemu-common.h" #include "qemu-common.h"
static void qstring_destroy_obj(QObject *obj);
static const QType qstring_type = {
.code = QTYPE_QSTRING,
.destroy = qstring_destroy_obj,
};
/** /**
* qstring_new(): Create a new empty QString * qstring_new(): Create a new empty QString
* *
@ -49,6 +42,7 @@ QString *qstring_from_substr(const char *str, int start, int end)
QString *qstring; QString *qstring;
qstring = g_malloc(sizeof(*qstring)); qstring = g_malloc(sizeof(*qstring));
qobject_init(QOBJECT(qstring), QTYPE_QSTRING);
qstring->length = end - start + 1; qstring->length = end - start + 1;
qstring->capacity = qstring->length; qstring->capacity = qstring->length;
@ -57,7 +51,6 @@ QString *qstring_from_substr(const char *str, int start, int end)
memcpy(qstring->string, str + start, qstring->length); memcpy(qstring->string, str + start, qstring->length);
qstring->string[qstring->length] = 0; qstring->string[qstring->length] = 0;
QOBJECT_INIT(qstring, &qstring_type);
return qstring; return qstring;
} }
@ -138,7 +131,7 @@ const char *qstring_get_str(const QString *qstring)
* qstring_destroy_obj(): Free all memory allocated by a QString * qstring_destroy_obj(): Free all memory allocated by a QString
* object * object
*/ */
static void qstring_destroy_obj(QObject *obj) void qstring_destroy_obj(QObject *obj)
{ {
QString *qs; QString *qs;

View File

@ -61,7 +61,7 @@ void replay_save_input_event(InputEvent *evt)
replay_put_dword(evt->u.key->key->u.qcode); replay_put_dword(evt->u.key->key->u.qcode);
replay_put_byte(evt->u.key->down); replay_put_byte(evt->u.key->down);
break; break;
case KEY_VALUE_KIND_MAX: case KEY_VALUE_KIND__MAX:
/* keep gcc happy */ /* keep gcc happy */
break; break;
} }
@ -78,7 +78,7 @@ void replay_save_input_event(InputEvent *evt)
replay_put_dword(evt->u.abs->axis); replay_put_dword(evt->u.abs->axis);
replay_put_qword(evt->u.abs->value); replay_put_qword(evt->u.abs->value);
break; break;
case INPUT_EVENT_KIND_MAX: case INPUT_EVENT_KIND__MAX:
/* keep gcc happy */ /* keep gcc happy */
break; break;
} }
@ -109,7 +109,7 @@ InputEvent *replay_read_input_event(void)
evt.u.key->key->u.qcode = (QKeyCode)replay_get_dword(); evt.u.key->key->u.qcode = (QKeyCode)replay_get_dword();
evt.u.key->down = replay_get_byte(); evt.u.key->down = replay_get_byte();
break; break;
case KEY_VALUE_KIND_MAX: case KEY_VALUE_KIND__MAX:
/* keep gcc happy */ /* keep gcc happy */
break; break;
} }
@ -129,7 +129,7 @@ InputEvent *replay_read_input_event(void)
evt.u.abs->axis = (InputAxis)replay_get_dword(); evt.u.abs->axis = (InputAxis)replay_get_dword();
evt.u.abs->value = replay_get_qword(); evt.u.abs->value = replay_get_qword();
break; break;
case INPUT_EVENT_KIND_MAX: case INPUT_EVENT_KIND__MAX:
/* keep gcc happy */ /* keep gcc happy */
break; break;
} }

View File

@ -36,54 +36,47 @@ struct %(c_name)s {
c_name=c_name(name), c_type=element_type.c_type()) c_name=c_name(name), c_type=element_type.c_type())
def gen_struct_field(member): def gen_struct_fields(members):
ret = '' ret = ''
for memb in members:
if member.optional: if memb.optional:
ret += mcgen(''' ret += mcgen('''
bool has_%(c_name)s; bool has_%(c_name)s;
''', ''',
c_name=c_name(member.name)) c_name=c_name(memb.name))
ret += mcgen(''' ret += mcgen('''
%(c_type)s %(c_name)s; %(c_type)s %(c_name)s;
''', ''',
c_type=member.type.c_type(), c_name=c_name(member.name)) c_type=memb.type.c_type(), c_name=c_name(memb.name))
return ret return ret
def gen_struct_fields(local_members, base=None): def gen_object(name, base, members, variants):
ret = ''
if base:
ret += mcgen('''
/* Members inherited from %(c_name)s: */
''',
c_name=base.c_name())
for memb in base.members:
ret += gen_struct_field(memb)
ret += mcgen('''
/* Own members: */
''')
for memb in local_members:
ret += gen_struct_field(memb)
return ret
def gen_struct(name, base, members):
ret = mcgen(''' ret = mcgen('''
struct %(c_name)s { struct %(c_name)s {
''', ''',
c_name=c_name(name)) c_name=c_name(name))
ret += gen_struct_fields(members, base) if base:
ret += mcgen('''
/* Members inherited from %(c_name)s: */
''',
c_name=base.c_name())
ret += gen_struct_fields(base.members)
ret += mcgen('''
/* Own members: */
''')
ret += gen_struct_fields(members)
if variants:
ret += gen_variants(variants)
# Make sure that all structs have at least one field; this avoids # Make sure that all structs have at least one field; this avoids
# potential issues with attempting to malloc space for zero-length # potential issues with attempting to malloc space for zero-length
# structs in C, and also incompatibility with C++ (where an empty # structs in C, and also incompatibility with C++ (where an empty
# struct is size 1). # struct is size 1).
if not (base and base.members) and not members: if not (base and base.members) and not members and not variants:
ret += mcgen(''' ret += mcgen('''
char qapi_dummy_field_for_empty_struct; char qapi_dummy_field_for_empty_struct;
''') ''')
@ -108,49 +101,7 @@ static inline %(base)s *qapi_%(c_name)s_base(const %(c_name)s *obj)
c_name=c_name(name), base=base.c_name()) c_name=c_name(name), base=base.c_name())
def gen_alternate_qtypes_decl(name): def gen_variants(variants):
return mcgen('''
extern const int %(c_name)s_qtypes[];
''',
c_name=c_name(name))
def gen_alternate_qtypes(name, variants):
ret = mcgen('''
const int %(c_name)s_qtypes[QTYPE_MAX] = {
''',
c_name=c_name(name))
for var in variants.variants:
qtype = var.type.alternate_qtype()
assert qtype
ret += mcgen('''
[%(qtype)s] = %(enum_const)s,
''',
qtype=qtype,
enum_const=c_enum_const(variants.tag_member.type.name,
var.name))
ret += mcgen('''
};
''')
return ret
def gen_union(name, base, variants):
ret = mcgen('''
struct %(c_name)s {
''',
c_name=c_name(name))
if base:
ret += gen_struct_fields([], base)
else:
ret += gen_struct_field(variants.tag_member)
# FIXME: What purpose does data serve, besides preventing a union that # FIXME: What purpose does data serve, besides preventing a union that
# has a branch named 'data'? We use it in qapi-visit.py to decide # has a branch named 'data'? We use it in qapi-visit.py to decide
# whether to bypass the switch statement if visiting the discriminator # whether to bypass the switch statement if visiting the discriminator
@ -159,7 +110,7 @@ struct %(c_name)s {
# should not be any data leaks even without a data pointer. Or, if # should not be any data leaks even without a data pointer. Or, if
# 'data' is merely added to guarantee we don't have an empty union, # 'data' is merely added to guarantee we don't have an empty union,
# shouldn't we enforce that at .json parse time? # shouldn't we enforce that at .json parse time?
ret += mcgen(''' ret = mcgen('''
union { /* union tag is @%(c_name)s */ union { /* union tag is @%(c_name)s */
void *data; void *data;
''', ''',
@ -176,7 +127,6 @@ struct %(c_name)s {
ret += mcgen(''' ret += mcgen('''
} u; } u;
};
''') ''')
return ret return ret
@ -218,21 +168,17 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
self.decl = None self.decl = None
self.defn = None self.defn = None
self._fwdecl = None self._fwdecl = None
self._fwdefn = None
self._btin = None self._btin = None
def visit_begin(self, schema): def visit_begin(self, schema):
self.decl = '' self.decl = ''
self.defn = '' self.defn = ''
self._fwdecl = '' self._fwdecl = ''
self._fwdefn = ''
self._btin = guardstart('QAPI_TYPES_BUILTIN') self._btin = guardstart('QAPI_TYPES_BUILTIN')
def visit_end(self): def visit_end(self):
self.decl = self._fwdecl + self.decl self.decl = self._fwdecl + self.decl
self._fwdecl = None self._fwdecl = None
self.defn = self._fwdefn + self.defn
self._fwdefn = None
# To avoid header dependency hell, we always generate # To avoid header dependency hell, we always generate
# declarations for built-in types in our header files and # declarations for built-in types in our header files and
# simply guard them. See also do_builtins (command line # simply guard them. See also do_builtins (command line
@ -251,8 +197,15 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
self.defn += gen_type_cleanup(name) self.defn += gen_type_cleanup(name)
def visit_enum_type(self, name, info, values, prefix): def visit_enum_type(self, name, info, values, prefix):
# Special case for our lone builtin enum type
# TODO use something cleaner than existence of info
if not info:
self._btin += gen_enum(name, values, prefix)
if do_builtins:
self.defn += gen_enum_lookup(name, values, prefix)
else:
self._fwdecl += gen_enum(name, values, prefix) self._fwdecl += gen_enum(name, values, prefix)
self._fwdefn += gen_enum_lookup(name, values, prefix) self.defn += gen_enum_lookup(name, values, prefix)
def visit_array_type(self, name, info, element_type): def visit_array_type(self, name, info, element_type):
if isinstance(element_type, QAPISchemaBuiltinType): if isinstance(element_type, QAPISchemaBuiltinType):
@ -268,20 +221,14 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
def visit_object_type(self, name, info, base, members, variants): def visit_object_type(self, name, info, base, members, variants):
self._fwdecl += gen_fwd_object_or_array(name) self._fwdecl += gen_fwd_object_or_array(name)
if variants: self.decl += gen_object(name, base, members, variants)
assert not members # not implemented
self.decl += gen_union(name, base, variants)
else:
self.decl += gen_struct(name, base, members)
if base: if base:
self.decl += gen_upcast(name, base) self.decl += gen_upcast(name, base)
self._gen_type_cleanup(name) self._gen_type_cleanup(name)
def visit_alternate_type(self, name, info, variants): def visit_alternate_type(self, name, info, variants):
self._fwdecl += gen_fwd_object_or_array(name) self._fwdecl += gen_fwd_object_or_array(name)
self._fwdefn += gen_alternate_qtypes(name, variants) self.decl += gen_object(name, None, [variants.tag_member], variants)
self.decl += gen_union(name, None, variants)
self.decl += gen_alternate_qtypes_decl(name)
self._gen_type_cleanup(name) self._gen_type_cleanup(name)
# If you link code generated from multiple schemata, you want only one # If you link code generated from multiple schemata, you want only one
@ -338,10 +285,11 @@ fdef.write(mcgen('''
''', ''',
prefix=prefix)) prefix=prefix))
# To avoid circular headers, use only typedefs.h here, not qobject.h
fdecl.write(mcgen(''' fdecl.write(mcgen('''
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "qapi/qmp/qobject.h" #include "qemu/typedefs.h"
''')) '''))
schema = QAPISchema(input_file) schema = QAPISchema(input_file)

View File

@ -172,6 +172,7 @@ out:
def gen_visit_enum(name): def gen_visit_enum(name):
# FIXME cast from enum *obj to int * invalidly assumes enum is int
return mcgen(''' return mcgen('''
void visit_type_%(c_name)s(Visitor *v, %(c_name)s *obj, const char *name, Error **errp) void visit_type_%(c_name)s(Visitor *v, %(c_name)s *obj, const char *name, Error **errp)
@ -183,6 +184,11 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s *obj, const char *name, Error
def gen_visit_alternate(name, variants): def gen_visit_alternate(name, variants):
promote_int = 'true'
for var in variants.variants:
if var.type.alternate_qtype() == 'QTYPE_QINT':
promote_int = 'false'
ret = mcgen(''' ret = mcgen('''
void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error **errp) void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error **errp)
@ -193,13 +199,13 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error
if (err) { if (err) {
goto out; goto out;
} }
visit_get_next_type(v, (int*) &(*obj)->type, %(c_name)s_qtypes, name, &err); visit_get_next_type(v, &(*obj)->type, %(promote_int)s, name, &err);
if (err) { if (err) {
goto out_obj; goto out_obj;
} }
switch ((*obj)->type) { switch ((*obj)->type) {
''', ''',
c_name=c_name(name)) c_name=c_name(name), promote_int=promote_int)
for var in variants.variants: for var in variants.variants:
ret += mcgen(''' ret += mcgen('''
@ -207,14 +213,14 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error
visit_type_%(c_type)s(v, &(*obj)->u.%(c_name)s, name, &err); visit_type_%(c_type)s(v, &(*obj)->u.%(c_name)s, name, &err);
break; break;
''', ''',
case=c_enum_const(variants.tag_member.type.name, case=var.type.alternate_qtype(),
var.name),
c_type=var.type.c_name(), c_type=var.type.c_name(),
c_name=c_name(var.name)) c_name=c_name(var.name))
ret += mcgen(''' ret += mcgen('''
default: default:
abort(); error_setg(&err, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
"%(name)s");
} }
out_obj: out_obj:
error_propagate(errp, err); error_propagate(errp, err);
@ -223,7 +229,8 @@ out_obj:
out: out:
error_propagate(errp, err); error_propagate(errp, err);
} }
''') ''',
name=name)
return ret return ret
@ -347,6 +354,13 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
isinstance(entity, QAPISchemaObjectType)) isinstance(entity, QAPISchemaObjectType))
def visit_enum_type(self, name, info, values, prefix): def visit_enum_type(self, name, info, values, prefix):
# Special case for our lone builtin enum type
# TODO use something cleaner than existence of info
if not info:
self._btin += gen_visit_decl(name, scalar=True)
if do_builtins:
self.defn += gen_visit_enum(name)
else:
self.decl += gen_visit_decl(name, scalar=True) self.decl += gen_visit_decl(name, scalar=True)
self.defn += gen_visit_enum(name) self.defn += gen_visit_enum(name)
@ -364,7 +378,10 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
def visit_object_type(self, name, info, base, members, variants): def visit_object_type(self, name, info, base, members, variants):
self.decl += gen_visit_decl(name) self.decl += gen_visit_decl(name)
if variants: if variants:
assert not members # not implemented if members:
# Members other than variants.tag_member not implemented
assert len(members) == 1
assert members[0] == variants.tag_member
self.defn += gen_visit_union(name, base, variants) self.defn += gen_visit_union(name, base, variants)
else: else:
self.defn += gen_visit_struct(name, base, members) self.defn += gen_visit_struct(name, base, members)
@ -427,6 +444,7 @@ fdef.write(mcgen('''
fdecl.write(mcgen(''' fdecl.write(mcgen('''
#include "qapi/visitor.h" #include "qapi/visitor.h"
#include "qapi/qmp/qerror.h"
#include "%(prefix)sqapi-types.h" #include "%(prefix)sqapi-types.h"
''', ''',

View File

@ -33,7 +33,8 @@ builtin_types = {
'uint32': 'QTYPE_QINT', 'uint32': 'QTYPE_QINT',
'uint64': 'QTYPE_QINT', 'uint64': 'QTYPE_QINT',
'size': 'QTYPE_QINT', 'size': 'QTYPE_QINT',
'any': None, # any qtype_code possible, actually 'any': None, # any QType possible, actually
'QType': 'QTYPE_QSTRING',
} }
# Whitelist of commands allowed to return a non-dictionary # Whitelist of commands allowed to return a non-dictionary
@ -58,6 +59,20 @@ returns_whitelist = [
'guest-sync-delimited', 'guest-sync-delimited',
] ]
# Whitelist of entities allowed to violate case conventions
case_whitelist = [
# From QMP:
'ACPISlotType', # DIMM, visible through query-acpi-ospm-status
'CpuInfoBase', # CPU, visible through query-cpu
'CpuInfoMIPS', # PC, visible through query-cpu
'CpuInfoTricore', # PC, visible through query-cpu
'InputAxis', # TODO: drop when x-input-send-event is fixed
'InputButton', # TODO: drop when x-input-send-event is fixed
'QapiErrorClass', # all members, visible through errors
'UuidInfo', # UUID, visible through query-uuid
'X86CPURegister32', # all members, visible indirectly through qom-get
]
enum_types = [] enum_types = []
struct_types = [] struct_types = []
union_types = [] union_types = []
@ -353,9 +368,11 @@ def discriminator_find_enum_define(expr):
return find_enum(discriminator_type) return find_enum(discriminator_type)
# FIXME should enforce "other than downstream extensions [...], all # Names must be letters, numbers, -, and _. They must start with letter,
# names should begin with a letter". # except for downstream extensions which must start with __RFQDN_.
valid_name = re.compile('^[a-zA-Z_][a-zA-Z0-9_.-]*$') # Dots are only valid in the downstream extension prefix.
valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
'[a-zA-Z][a-zA-Z0-9_-]*$')
def check_name(expr_info, source, name, allow_optional=False, def check_name(expr_info, source, name, allow_optional=False,
@ -374,8 +391,8 @@ def check_name(expr_info, source, name, allow_optional=False,
% (source, name)) % (source, name))
# Enum members can start with a digit, because the generated C # Enum members can start with a digit, because the generated C
# code always prefixes it with the enum name # code always prefixes it with the enum name
if enum_member: if enum_member and membername[0].isdigit():
membername = '_' + membername membername = 'D' + membername
# Reserve the entire 'q_' namespace for c_name() # Reserve the entire 'q_' namespace for c_name()
if not valid_name.match(membername) or \ if not valid_name.match(membername) or \
c_name(membername, False).startswith('q_'): c_name(membername, False).startswith('q_'):
@ -502,21 +519,6 @@ def check_type(expr_info, source, value, allow_array=False,
'enum']) 'enum'])
def check_member_clash(expr_info, base_name, data, source=""):
base = find_struct(base_name)
assert base
base_members = base['data']
for key in data.keys():
if key.startswith('*'):
key = key[1:]
if key in base_members or "*" + key in base_members:
raise QAPIExprError(expr_info,
"Member name '%s'%s clashes with base '%s'"
% (key, source, base_name))
if base.get('base'):
check_member_clash(expr_info, base['base'], data, source)
def check_command(expr, expr_info): def check_command(expr, expr_info):
name = expr['command'] name = expr['command']
@ -535,8 +537,6 @@ def check_event(expr, expr_info):
global events global events
name = expr['event'] name = expr['event']
if name.upper() == 'MAX':
raise QAPIExprError(expr_info, "Event name 'MAX' cannot be created")
events.append(name) events.append(name)
check_type(expr_info, "'data' for event '%s'" % name, check_type(expr_info, "'data' for event '%s'" % name,
expr.get('data'), allow_dict=True, allow_optional=True, expr.get('data'), allow_dict=True, allow_optional=True,
@ -548,8 +548,6 @@ def check_union(expr, expr_info):
base = expr.get('base') base = expr.get('base')
discriminator = expr.get('discriminator') discriminator = expr.get('discriminator')
members = expr['data'] members = expr['data']
values = {'MAX': '(automatic)', 'KIND': '(automatic)',
'TYPE': '(automatic)'}
# Two types of unions, determined by discriminator. # Two types of unions, determined by discriminator.
@ -596,59 +594,29 @@ def check_union(expr, expr_info):
for (key, value) in members.items(): for (key, value) in members.items():
check_name(expr_info, "Member of union '%s'" % name, key) check_name(expr_info, "Member of union '%s'" % name, key)
# Each value must name a known type; furthermore, in flat unions, # Each value must name a known type
# branches must be a struct with no overlapping member names
check_type(expr_info, "Member '%s' of union '%s'" % (key, name), check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
value, allow_array=not base, allow_metas=allow_metas) value, allow_array=not base, allow_metas=allow_metas)
if base:
branch_struct = find_struct(value)
assert branch_struct
check_member_clash(expr_info, base, branch_struct['data'],
" of branch '%s'" % key)
# If the discriminator names an enum type, then all members # If the discriminator names an enum type, then all members
# of 'data' must also be members of the enum type, which in turn # of 'data' must also be members of the enum type.
# must not collide with the discriminator name.
if enum_define: if enum_define:
if key not in enum_define['enum_values']: if key not in enum_define['enum_values']:
raise QAPIExprError(expr_info, raise QAPIExprError(expr_info,
"Discriminator value '%s' is not found in " "Discriminator value '%s' is not found in "
"enum '%s'" % "enum '%s'" %
(key, enum_define["enum_name"])) (key, enum_define["enum_name"]))
if discriminator in enum_define['enum_values']:
raise QAPIExprError(expr_info,
"Discriminator name '%s' collides with "
"enum value in '%s'" %
(discriminator, enum_define["enum_name"]))
# Otherwise, check for conflicts in the generated enum
else:
c_key = camel_to_upper(key)
if c_key in values:
raise QAPIExprError(expr_info,
"Union '%s' member '%s' clashes with '%s'"
% (name, key, values[c_key]))
values[c_key] = key
def check_alternate(expr, expr_info): def check_alternate(expr, expr_info):
name = expr['alternate'] name = expr['alternate']
members = expr['data'] members = expr['data']
values = {'MAX': '(automatic)'}
types_seen = {} types_seen = {}
# Check every branch # Check every branch
for (key, value) in members.items(): for (key, value) in members.items():
check_name(expr_info, "Member of alternate '%s'" % name, key) check_name(expr_info, "Member of alternate '%s'" % name, key)
# Check for conflicts in the generated enum
c_key = camel_to_upper(key)
if c_key in values:
raise QAPIExprError(expr_info,
"Alternate '%s' member '%s' clashes with '%s'"
% (name, key, values[c_key]))
values[c_key] = key
# Ensure alternates have no type conflicts. # Ensure alternates have no type conflicts.
check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name), check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
value, value,
@ -667,7 +635,6 @@ def check_enum(expr, expr_info):
name = expr['enum'] name = expr['enum']
members = expr.get('data') members = expr.get('data')
prefix = expr.get('prefix') prefix = expr.get('prefix')
values = {'MAX': '(automatic)'}
if not isinstance(members, list): if not isinstance(members, list):
raise QAPIExprError(expr_info, raise QAPIExprError(expr_info,
@ -678,12 +645,6 @@ def check_enum(expr, expr_info):
for member in members: for member in members:
check_name(expr_info, "Member of enum '%s'" % name, member, check_name(expr_info, "Member of enum '%s'" % name, member,
enum_member=True) enum_member=True)
key = camel_to_upper(member)
if key in values:
raise QAPIExprError(expr_info,
"Enum '%s' member '%s' clashes with '%s'"
% (name, member, values[key]))
values[key] = member
def check_struct(expr, expr_info): def check_struct(expr, expr_info):
@ -694,8 +655,6 @@ def check_struct(expr, expr_info):
allow_dict=True, allow_optional=True) allow_dict=True, allow_optional=True)
check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'), check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
allow_metas=['struct']) allow_metas=['struct'])
if expr.get('base'):
check_member_clash(expr_info, expr['base'], expr['data'])
def check_keys(expr_elem, meta, required, optional=[]): def check_keys(expr_elem, meta, required, optional=[]):
@ -907,13 +866,16 @@ class QAPISchemaEnumType(QAPISchemaType):
def __init__(self, name, info, values, prefix): def __init__(self, name, info, values, prefix):
QAPISchemaType.__init__(self, name, info) QAPISchemaType.__init__(self, name, info)
for v in values: for v in values:
assert isinstance(v, str) assert isinstance(v, QAPISchemaMember)
v.set_owner(name)
assert prefix is None or isinstance(prefix, str) assert prefix is None or isinstance(prefix, str)
self.values = values self.values = values
self.prefix = prefix self.prefix = prefix
def check(self, schema): def check(self, schema):
assert len(set(self.values)) == len(self.values) seen = {}
for v in self.values:
v.check_clash(self.info, seen)
def is_implicit(self): def is_implicit(self):
# See QAPISchema._make_implicit_enum_type() # See QAPISchema._make_implicit_enum_type()
@ -922,8 +884,11 @@ class QAPISchemaEnumType(QAPISchemaType):
def c_type(self, is_param=False): def c_type(self, is_param=False):
return c_name(self.name) return c_name(self.name)
def member_names(self):
return [v.name for v in self.values]
def c_null(self): def c_null(self):
return c_enum_const(self.name, (self.values + ['MAX'])[0], return c_enum_const(self.name, (self.member_names() + ['_MAX'])[0],
self.prefix) self.prefix)
def json_type(self): def json_type(self):
@ -931,7 +896,7 @@ class QAPISchemaEnumType(QAPISchemaType):
def visit(self, visitor): def visit(self, visitor):
visitor.visit_enum_type(self.name, self.info, visitor.visit_enum_type(self.name, self.info,
self.values, self.prefix) self.member_names(), self.prefix)
class QAPISchemaArrayType(QAPISchemaType): class QAPISchemaArrayType(QAPISchemaType):
@ -957,12 +922,17 @@ class QAPISchemaArrayType(QAPISchemaType):
class QAPISchemaObjectType(QAPISchemaType): class QAPISchemaObjectType(QAPISchemaType):
def __init__(self, name, info, base, local_members, variants): def __init__(self, name, info, base, local_members, variants):
# struct has local_members, optional base, and no variants
# flat union has base, variants, and no local_members
# simple union has local_members, variants, and no base
QAPISchemaType.__init__(self, name, info) QAPISchemaType.__init__(self, name, info)
assert base is None or isinstance(base, str) assert base is None or isinstance(base, str)
for m in local_members: for m in local_members:
assert isinstance(m, QAPISchemaObjectTypeMember) assert isinstance(m, QAPISchemaObjectTypeMember)
assert (variants is None or m.set_owner(name)
isinstance(variants, QAPISchemaObjectTypeVariants)) if variants is not None:
assert isinstance(variants, QAPISchemaObjectTypeVariants)
variants.set_owner(name)
self._base_name = base self._base_name = base
self.base = None self.base = None
self.local_members = local_members self.local_members = local_members
@ -970,27 +940,34 @@ class QAPISchemaObjectType(QAPISchemaType):
self.members = None self.members = None
def check(self, schema): def check(self, schema):
assert self.members is not False # not running in cycles if self.members is False: # check for cycles
raise QAPIExprError(self.info,
"Object %s contains itself" % self.name)
if self.members: if self.members:
return return
self.members = False # mark as being checked self.members = False # mark as being checked
seen = OrderedDict()
if self._base_name: if self._base_name:
self.base = schema.lookup_type(self._base_name) self.base = schema.lookup_type(self._base_name)
assert isinstance(self.base, QAPISchemaObjectType) assert isinstance(self.base, QAPISchemaObjectType)
assert not self.base.variants # not implemented
self.base.check(schema) self.base.check(schema)
members = list(self.base.members) self.base.check_clash(schema, self.info, seen)
else:
members = []
seen = {}
for m in members:
assert c_name(m.name) not in seen
seen[m.name] = m
for m in self.local_members: for m in self.local_members:
m.check(schema, members, seen) m.check(schema)
m.check_clash(self.info, seen)
self.members = seen.values()
if self.variants: if self.variants:
self.variants.check(schema, members, seen) self.variants.check(schema, seen)
self.members = members assert self.variants.tag_member in self.members
self.variants.check_clash(schema, self.info, seen)
# Check that the members of this type do not cause duplicate JSON fields,
# and update seen to track the members seen so far. Report any errors
# on behalf of info, which is not necessarily self.info
def check_clash(self, schema, info, seen):
assert not self.variants # not implemented
for m in self.members:
m.check_clash(info, seen)
def is_implicit(self): def is_implicit(self):
# See QAPISchema._make_implicit_object_type() # See QAPISchema._make_implicit_object_type()
@ -1014,22 +991,63 @@ class QAPISchemaObjectType(QAPISchemaType):
self.members, self.variants) self.members, self.variants)
class QAPISchemaObjectTypeMember(object): class QAPISchemaMember(object):
def __init__(self, name, typ, optional): role = 'member'
def __init__(self, name):
assert isinstance(name, str) assert isinstance(name, str)
self.name = name
self.owner = None
def set_owner(self, name):
assert not self.owner
self.owner = name
def check_clash(self, info, seen):
cname = c_name(self.name)
if cname.lower() != cname and self.owner not in case_whitelist:
raise QAPIExprError(info,
"%s should not use uppercase" % self.describe())
if cname in seen:
raise QAPIExprError(info,
"%s collides with %s"
% (self.describe(), seen[cname].describe()))
seen[cname] = self
def _pretty_owner(self):
owner = self.owner
if owner.startswith(':obj-'):
# See QAPISchema._make_implicit_object_type() - reverse the
# mapping there to create a nice human-readable description
owner = owner[5:]
if owner.endswith('-arg'):
return '(parameter of %s)' % owner[:-4]
else:
assert owner.endswith('-wrapper')
# Unreachable and not implemented
assert False
if owner.endswith('Kind'):
# See QAPISchema._make_implicit_enum_type()
return '(branch of %s)' % owner[:-4]
return '(%s of %s)' % (self.role, owner)
def describe(self):
return "'%s' %s" % (self.name, self._pretty_owner())
class QAPISchemaObjectTypeMember(QAPISchemaMember):
def __init__(self, name, typ, optional):
QAPISchemaMember.__init__(self, name)
assert isinstance(typ, str) assert isinstance(typ, str)
assert isinstance(optional, bool) assert isinstance(optional, bool)
self.name = name
self._type_name = typ self._type_name = typ
self.type = None self.type = None
self.optional = optional self.optional = optional
def check(self, schema, all_members, seen): def check(self, schema):
assert self.name not in seen assert self.owner
self.type = schema.lookup_type(self._type_name) self.type = schema.lookup_type(self._type_name)
assert self.type assert self.type
all_members.append(self)
seen[self.name] = self
class QAPISchemaObjectTypeVariants(object): class QAPISchemaObjectTypeVariants(object):
@ -1047,25 +1065,38 @@ class QAPISchemaObjectTypeVariants(object):
self.tag_member = tag_member self.tag_member = tag_member
self.variants = variants self.variants = variants
def check(self, schema, members, seen): def set_owner(self, name):
if self.tag_name: for v in self.variants:
self.tag_member = seen[self.tag_name] v.set_owner(name)
else:
self.tag_member.check(schema, members, seen) def check(self, schema, seen):
if not self.tag_member: # flat union
self.tag_member = seen[c_name(self.tag_name)]
assert self.tag_name == self.tag_member.name
assert isinstance(self.tag_member.type, QAPISchemaEnumType) assert isinstance(self.tag_member.type, QAPISchemaEnumType)
for v in self.variants: for v in self.variants:
vseen = dict(seen) v.check(schema)
v.check(schema, self.tag_member.type, vseen) # Union names must match enum values; alternate names are
# checked separately. Use 'seen' to tell the two apart.
if seen:
assert v.name in self.tag_member.type.member_names()
assert isinstance(v.type, QAPISchemaObjectType)
v.type.check(schema)
def check_clash(self, schema, info, seen):
for v in self.variants:
# Reset seen map for each variant, since qapi names from one
# branch do not affect another branch
assert isinstance(v.type, QAPISchemaObjectType)
v.type.check_clash(schema, info, dict(seen))
class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember): class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
role = 'branch'
def __init__(self, name, typ): def __init__(self, name, typ):
QAPISchemaObjectTypeMember.__init__(self, name, typ, False) QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
def check(self, schema, tag_type, seen):
QAPISchemaObjectTypeMember.check(self, schema, [], seen)
assert self.name in tag_type.values
# This function exists to support ugly simple union special cases # This function exists to support ugly simple union special cases
# TODO get rid of them, and drop the function # TODO get rid of them, and drop the function
def simple_union_type(self): def simple_union_type(self):
@ -1082,10 +1113,20 @@ class QAPISchemaAlternateType(QAPISchemaType):
QAPISchemaType.__init__(self, name, info) QAPISchemaType.__init__(self, name, info)
assert isinstance(variants, QAPISchemaObjectTypeVariants) assert isinstance(variants, QAPISchemaObjectTypeVariants)
assert not variants.tag_name assert not variants.tag_name
variants.set_owner(name)
variants.tag_member.set_owner(self.name)
self.variants = variants self.variants = variants
def check(self, schema): def check(self, schema):
self.variants.check(schema, [], {}) self.variants.tag_member.check(schema)
# Not calling self.variants.check_clash(), because there's nothing
# to clash with
self.variants.check(schema, {})
# Alternate branch names have no relation to the tag enum values;
# so we have to check for potential name collisions ourselves.
seen = {}
for v in self.variants.variants:
v.check_clash(self.info, seen)
def json_type(self): def json_type(self):
return 'value' return 'value'
@ -1196,10 +1237,20 @@ class QAPISchema(object):
self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None, self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
[], None) [], None)
self._def_entity(self.the_empty_object_type) self._def_entity(self.the_empty_object_type)
qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
'qstring', 'qdict', 'qlist',
'qfloat', 'qbool'])
self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
'QTYPE'))
def _make_enum_members(self, values):
return [QAPISchemaMember(v) for v in values]
def _make_implicit_enum_type(self, name, info, values): def _make_implicit_enum_type(self, name, info, values):
# See also QAPISchemaObjectTypeMember._pretty_owner()
name = name + 'Kind' # Use namespace reserved by add_name() name = name + 'Kind' # Use namespace reserved by add_name()
self._def_entity(QAPISchemaEnumType(name, info, values, None)) self._def_entity(QAPISchemaEnumType(
name, info, self._make_enum_members(values), None))
return name return name
def _make_array_type(self, element_type, info): def _make_array_type(self, element_type, info):
@ -1211,6 +1262,7 @@ class QAPISchema(object):
def _make_implicit_object_type(self, name, info, role, members): def _make_implicit_object_type(self, name, info, role, members):
if not members: if not members:
return None return None
# See also QAPISchemaObjectTypeMember._pretty_owner()
name = ':obj-%s-%s' % (name, role) name = ':obj-%s-%s' % (name, role)
if not self.lookup_entity(name, QAPISchemaObjectType): if not self.lookup_entity(name, QAPISchemaObjectType):
self._def_entity(QAPISchemaObjectType(name, info, None, self._def_entity(QAPISchemaObjectType(name, info, None,
@ -1221,7 +1273,8 @@ class QAPISchema(object):
name = expr['enum'] name = expr['enum']
data = expr['data'] data = expr['data']
prefix = expr.get('prefix') prefix = expr.get('prefix')
self._def_entity(QAPISchemaEnumType(name, info, data, prefix)) self._def_entity(QAPISchemaEnumType(
name, info, self._make_enum_members(data), prefix))
def _make_member(self, name, typ, info): def _make_member(self, name, typ, info):
optional = False optional = False
@ -1256,11 +1309,6 @@ class QAPISchema(object):
typ, info, 'wrapper', [self._make_member('data', typ, info)]) typ, info, 'wrapper', [self._make_member('data', typ, info)])
return QAPISchemaObjectTypeVariant(case, typ) return QAPISchemaObjectTypeVariant(case, typ)
def _make_implicit_tag(self, type_name, info, variants):
typ = self._make_implicit_enum_type(type_name, info,
[v.name for v in variants])
return QAPISchemaObjectTypeMember('type', typ, False)
def _def_union_type(self, expr, info): def _def_union_type(self, expr, info):
name = expr['union'] name = expr['union']
data = expr['data'] data = expr['data']
@ -1270,13 +1318,16 @@ class QAPISchema(object):
if tag_name: if tag_name:
variants = [self._make_variant(key, value) variants = [self._make_variant(key, value)
for (key, value) in data.iteritems()] for (key, value) in data.iteritems()]
members = []
else: else:
variants = [self._make_simple_variant(key, value, info) variants = [self._make_simple_variant(key, value, info)
for (key, value) in data.iteritems()] for (key, value) in data.iteritems()]
tag_member = self._make_implicit_tag(name, info, variants) typ = self._make_implicit_enum_type(name, info,
[v.name for v in variants])
tag_member = QAPISchemaObjectTypeMember('type', typ, False)
members = [tag_member]
self._def_entity( self._def_entity(
QAPISchemaObjectType(name, info, base, QAPISchemaObjectType(name, info, base, members,
self._make_members(OrderedDict(), info),
QAPISchemaObjectTypeVariants(tag_name, QAPISchemaObjectTypeVariants(tag_name,
tag_member, tag_member,
variants))) variants)))
@ -1286,7 +1337,7 @@ class QAPISchema(object):
data = expr['data'] data = expr['data']
variants = [self._make_variant(key, value) variants = [self._make_variant(key, value)
for (key, value) in data.iteritems()] for (key, value) in data.iteritems()]
tag_member = self._make_implicit_tag(name, info, variants) tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
self._def_entity( self._def_entity(
QAPISchemaAlternateType(name, info, QAPISchemaAlternateType(name, info,
QAPISchemaObjectTypeVariants(None, QAPISchemaObjectTypeVariants(None,
@ -1390,7 +1441,7 @@ def camel_to_upper(value):
def c_enum_const(type_name, const_name, prefix=None): def c_enum_const(type_name, const_name, prefix=None):
if prefix is not None: if prefix is not None:
type_name = prefix type_name = prefix
return camel_to_upper(type_name + '_' + const_name) return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
c_name_trans = string.maketrans('.-', '__') c_name_trans = string.maketrans('.-', '__')
@ -1432,10 +1483,11 @@ def c_name(name, protect=True):
'not_eq', 'or', 'or_eq', 'xor', 'xor_eq']) 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
# namespace pollution: # namespace pollution:
polluted_words = set(['unix', 'errno']) polluted_words = set(['unix', 'errno'])
name = name.translate(c_name_trans)
if protect and (name in c89_words | c99_words | c11_words | gcc_words if protect and (name in c89_words | c99_words | c11_words | gcc_words
| cpp_words | polluted_words): | cpp_words | polluted_words):
return "q_" + name return "q_" + name
return name.translate(c_name_trans) return name
eatspace = '\033EATSPACE.' eatspace = '\033EATSPACE.'
pointer_suffix = ' *' + eatspace pointer_suffix = ' *' + eatspace
@ -1515,7 +1567,7 @@ const char *const %(c_name)s_lookup[] = {
''', ''',
index=index, value=value) index=index, value=value)
max_index = c_enum_const(name, 'MAX', prefix) max_index = c_enum_const(name, '_MAX', prefix)
ret += mcgen(''' ret += mcgen('''
[%(max_index)s] = NULL, [%(max_index)s] = NULL,
}; };
@ -1526,7 +1578,7 @@ const char *const %(c_name)s_lookup[] = {
def gen_enum(name, values, prefix=None): def gen_enum(name, values, prefix=None):
# append automatically generated _MAX value # append automatically generated _MAX value
enum_values = values + ['MAX'] enum_values = values + ['_MAX']
ret = mcgen(''' ret = mcgen('''
@ -1594,15 +1646,10 @@ def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False):
for memb in members: for memb in members:
if memb.optional: if memb.optional:
ret += mcgen(''' ret += mcgen('''
visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s", %(errp)s); if (visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s")) {
''', ''',
prefix=prefix, c_name=c_name(memb.name), prefix=prefix, c_name=c_name(memb.name),
name=memb.name, errp=errparg) name=memb.name, errp=errparg)
ret += gen_err_check(skiperr=skiperr)
ret += mcgen('''
if (%(prefix)shas_%(c_name)s) {
''',
prefix=prefix, c_name=c_name(memb.name))
push_indent() push_indent()
# Ugly: sometimes we need to cast away const # Ugly: sometimes we need to cast away const

View File

@ -246,6 +246,7 @@ qapi-schema += args-array-unknown.json
qapi-schema += args-int.json qapi-schema += args-int.json
qapi-schema += args-invalid.json qapi-schema += args-invalid.json
qapi-schema += args-member-array-bad.json qapi-schema += args-member-array-bad.json
qapi-schema += args-member-case.json
qapi-schema += args-member-unknown.json qapi-schema += args-member-unknown.json
qapi-schema += args-name-clash.json qapi-schema += args-name-clash.json
qapi-schema += args-union.json qapi-schema += args-union.json
@ -256,6 +257,8 @@ qapi-schema += bad-ident.json
qapi-schema += bad-type-bool.json qapi-schema += bad-type-bool.json
qapi-schema += bad-type-dict.json qapi-schema += bad-type-dict.json
qapi-schema += bad-type-int.json qapi-schema += bad-type-int.json
qapi-schema += base-cycle-direct.json
qapi-schema += base-cycle-indirect.json
qapi-schema += command-int.json qapi-schema += command-int.json
qapi-schema += comments.json qapi-schema += comments.json
qapi-schema += double-data.json qapi-schema += double-data.json
@ -267,23 +270,20 @@ qapi-schema += enum-bad-prefix.json
qapi-schema += enum-clash-member.json qapi-schema += enum-clash-member.json
qapi-schema += enum-dict-member.json qapi-schema += enum-dict-member.json
qapi-schema += enum-int-member.json qapi-schema += enum-int-member.json
qapi-schema += enum-max-member.json qapi-schema += enum-member-case.json
qapi-schema += enum-missing-data.json qapi-schema += enum-missing-data.json
qapi-schema += enum-wrong-data.json qapi-schema += enum-wrong-data.json
qapi-schema += escape-outside-string.json qapi-schema += escape-outside-string.json
qapi-schema += escape-too-big.json qapi-schema += escape-too-big.json
qapi-schema += escape-too-short.json qapi-schema += escape-too-short.json
qapi-schema += event-case.json qapi-schema += event-case.json
qapi-schema += event-max.json
qapi-schema += event-nest-struct.json qapi-schema += event-nest-struct.json
qapi-schema += flat-union-array-branch.json qapi-schema += flat-union-array-branch.json
qapi-schema += flat-union-bad-base.json qapi-schema += flat-union-bad-base.json
qapi-schema += flat-union-bad-discriminator.json qapi-schema += flat-union-bad-discriminator.json
qapi-schema += flat-union-base-any.json qapi-schema += flat-union-base-any.json
qapi-schema += flat-union-base-union.json qapi-schema += flat-union-base-union.json
qapi-schema += flat-union-clash-branch.json
qapi-schema += flat-union-clash-member.json qapi-schema += flat-union-clash-member.json
qapi-schema += flat-union-clash-type.json
qapi-schema += flat-union-empty.json qapi-schema += flat-union-empty.json
qapi-schema += flat-union-inline.json qapi-schema += flat-union-inline.json
qapi-schema += flat-union-int-branch.json qapi-schema += flat-union-int-branch.json
@ -320,9 +320,11 @@ qapi-schema += redefined-command.json
qapi-schema += redefined-event.json qapi-schema += redefined-event.json
qapi-schema += redefined-type.json qapi-schema += redefined-type.json
qapi-schema += reserved-command-q.json qapi-schema += reserved-command-q.json
qapi-schema += reserved-enum-q.json
qapi-schema += reserved-member-has.json qapi-schema += reserved-member-has.json
qapi-schema += reserved-member-q.json qapi-schema += reserved-member-q.json
qapi-schema += reserved-member-u.json qapi-schema += reserved-member-u.json
qapi-schema += reserved-member-underscore.json
qapi-schema += reserved-type-kind.json qapi-schema += reserved-type-kind.json
qapi-schema += reserved-type-list.json qapi-schema += reserved-type-list.json
qapi-schema += returns-alternate.json qapi-schema += returns-alternate.json
@ -341,14 +343,12 @@ qapi-schema += unclosed-list.json
qapi-schema += unclosed-object.json qapi-schema += unclosed-object.json
qapi-schema += unclosed-string.json qapi-schema += unclosed-string.json
qapi-schema += unicode-str.json qapi-schema += unicode-str.json
qapi-schema += union-bad-branch.json
qapi-schema += union-base-no-discriminator.json qapi-schema += union-base-no-discriminator.json
qapi-schema += union-branch-case.json
qapi-schema += union-clash-branches.json qapi-schema += union-clash-branches.json
qapi-schema += union-clash-data.json qapi-schema += union-clash-data.json
qapi-schema += union-clash-type.json
qapi-schema += union-empty.json qapi-schema += union-empty.json
qapi-schema += union-invalid-base.json qapi-schema += union-invalid-base.json
qapi-schema += union-max.json
qapi-schema += union-optional-branch.json qapi-schema += union-optional-branch.json
qapi-schema += union-unknown.json qapi-schema += union-unknown.json
qapi-schema += unknown-escape.json qapi-schema += unknown-escape.json

View File

@ -1 +1 @@
tests/qapi-schema/alternate-clash.json:7: Alternate 'Alt1' member 'a_b' clashes with 'a-b' tests/qapi-schema/alternate-clash.json:7: 'a_b' (branch of Alt1) collides with 'a-b' (branch of Alt1)

View File

@ -1,4 +1,5 @@
object :empty object :empty
alternate Alt alternate Alt
case i: int case i: int
enum AltKind ['i'] enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
prefix QTYPE

View File

@ -0,0 +1 @@
tests/qapi-schema/args-member-case.json:2: 'Arg' (parameter of no-way-this-will-get-whitelisted) should not use uppercase

View File

@ -0,0 +1,2 @@
# Member names should be 'lower-case' unless the struct/command is whitelisted
{ 'command': 'no-way-this-will-get-whitelisted', 'data': { 'Arg': 'int' } }

View File

@ -0,0 +1 @@
tests/qapi-schema/args-name-clash.json:4: 'a_b' (parameter of oops) collides with 'a-b' (parameter of oops)

View File

@ -1 +1 @@
0 1

View File

@ -1,5 +1,4 @@
# C member name collision # C member name collision
# FIXME - This parses, but fails to compile, because the C struct is given # Reject members that clash when mapped to C names (we would have two 'a_b'
# two 'a_b' members. Either reject this at parse time, or munge the C names # members).
# to avoid the collision.
{ 'command': 'oops', 'data': { 'a-b': 'str', 'a_b': 'str' } } { 'command': 'oops', 'data': { 'a-b': 'str', 'a_b': 'str' } }

View File

@ -1,6 +0,0 @@
object :empty
object :obj-oops-arg
member a-b: str optional=False
member a_b: str optional=False
command oops :obj-oops-arg -> None
gen=True success_response=True

View File

@ -0,0 +1 @@
tests/qapi-schema/base-cycle-direct.json:2: Object Loopy contains itself

View File

@ -0,0 +1,2 @@
# we reject a loop in base classes
{ 'struct': 'Loopy', 'base': 'Loopy', 'data': {} }

View File

@ -0,0 +1 @@
tests/qapi-schema/base-cycle-indirect.json:2: Object Base1 contains itself

View File

@ -0,0 +1,3 @@
# we reject a loop in base classes
{ 'struct': 'Base1', 'base': 'Base2', 'data': {} }
{ 'struct': 'Base2', 'base': 'Base1', 'data': {} }

View File

@ -1,2 +1,4 @@
object :empty object :empty
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
prefix QTYPE
enum Status ['good', 'bad', 'ugly'] enum Status ['good', 'bad', 'ugly']

View File

@ -1 +1,3 @@
object :empty object :empty
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
prefix QTYPE

View File

@ -1 +1 @@
tests/qapi-schema/enum-clash-member.json:2: Enum 'MyEnum' member 'ONE' clashes with 'one' tests/qapi-schema/enum-clash-member.json:2: 'one_two' (member of MyEnum) collides with 'one-two' (member of MyEnum)

View File

@ -1,2 +1,2 @@
# we reject enums where members will clash when mapped to C enum # we reject enums where members will clash when mapped to C enum
{ 'enum': 'MyEnum', 'data': [ 'one', 'ONE' ] } { 'enum': 'MyEnum', 'data': [ 'one-two', 'one_two' ] }

View File

@ -1 +0,0 @@
tests/qapi-schema/enum-max-member.json:3: Enum 'MyEnum' member 'max' clashes with '(automatic)'

View File

@ -1,3 +0,0 @@
# we reject user-supplied 'max' for clashing with implicit enum end
# TODO: should we instead munge the implicit value to avoid the clash?
{ 'enum': 'MyEnum', 'data': [ 'max' ] }

View File

@ -0,0 +1 @@
tests/qapi-schema/enum-member-case.json:3: 'Value' (member of NoWayThisWillGetWhitelisted) should not use uppercase

View File

@ -0,0 +1,3 @@
# Member names should be 'lower-case' unless the enum is whitelisted
{ 'enum': 'UuidInfo', 'data': [ 'Value' ] } # UuidInfo is whitelisted
{ 'enum': 'NoWayThisWillGetWhitelisted', 'data': [ 'Value' ] }

View File

@ -1,2 +1,4 @@
object :empty object :empty
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
prefix QTYPE
event oops None event oops None

View File

@ -1 +0,0 @@
tests/qapi-schema/event-max.json:2: Event name 'MAX' cannot be created

View File

@ -1,2 +0,0 @@
# an event named 'MAX' would conflict with implicit C enum
{ 'event': 'MAX' }

View File

@ -1,18 +0,0 @@
# Flat union branch name collision
# FIXME: this parses, but then fails to compile due to a duplicate 'c_d'
# (one from the base member, the other from the branch name). We should
# either reject the collision at parse time, or munge the generated branch
# name to allow this to compile.
{ 'enum': 'TestEnum',
'data': [ 'base', 'c-d' ] }
{ 'struct': 'Base',
'data': { 'enum1': 'TestEnum', '*c_d': 'str' } }
{ 'struct': 'Branch1',
'data': { 'string': 'str' } }
{ 'struct': 'Branch2',
'data': { 'value': 'int' } }
{ 'union': 'TestUnion',
'base': 'Base',
'discriminator': 'enum1',
'data': { 'base': 'Branch1',
'c-d': 'Branch2' } }

View File

@ -1,14 +0,0 @@
object :empty
object Base
member enum1: TestEnum optional=False
member c_d: str optional=True
object Branch1
member string: str optional=False
object Branch2
member value: int optional=False
enum TestEnum ['base', 'c-d']
object TestUnion
base Base
tag enum1
case base: Branch1
case c-d: Branch2

View File

@ -1 +1 @@
tests/qapi-schema/flat-union-clash-member.json:11: Member name 'name' of branch 'value1' clashes with base 'Base' tests/qapi-schema/flat-union-clash-member.json:11: 'name' (member of Branch1) collides with 'name' (member of Base)

View File

@ -1 +0,0 @@
tests/qapi-schema/flat-union-clash-type.json:11: Discriminator name 'type' collides with enum value in 'TestEnum'

View File

@ -1,14 +0,0 @@
# Flat union branch 'type'
# Reject this, because we would have a clash in generated C, between the
# outer tag 'type' and the branch name 'type' within the union.
# TODO: We could munge the generated C branch name to let it compile.
{ 'enum': 'TestEnum',
'data': [ 'type' ] }
{ 'struct': 'Base',
'data': { 'type': 'TestEnum' } }
{ 'struct': 'Branch1',
'data': { 'string': 'str' } }
{ 'union': 'TestUnion',
'base': 'Base',
'discriminator': 'type',
'data': { 'type': 'Branch1' } }

View File

@ -2,6 +2,8 @@ object :empty
object Base object Base
member type: Empty optional=False member type: Empty optional=False
enum Empty [] enum Empty []
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
prefix QTYPE
object Union object Union
base Base base Base
tag type tag type

View File

@ -1,5 +1,7 @@
object :empty object :empty
object :obj-fooA-arg object :obj-fooA-arg
member bar1: str optional=False member bar1: str optional=False
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
prefix QTYPE
command fooA :obj-fooA-arg -> None command fooA :obj-fooA-arg -> None
gen=True success_response=True gen=True success_response=True

View File

@ -1,2 +1,4 @@
object :empty object :empty
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
prefix QTYPE
enum Status ['good', 'bad', 'ugly'] enum Status ['good', 'bad', 'ugly']

Some files were not shown because too many files have changed in this diff Show More