/* * QMP commands related to stats * * This work is licensed under the terms of the GNU GPL, version 2 or * (at your option) any later version. */ #include "qemu/osdep.h" #include "sysemu/stats.h" #include "qapi/qapi-commands-stats.h" #include "qemu/queue.h" #include "qapi/error.h" typedef struct StatsCallbacks { StatsProvider provider; StatRetrieveFunc *stats_cb; SchemaRetrieveFunc *schemas_cb; QTAILQ_ENTRY(StatsCallbacks) next; } StatsCallbacks; static QTAILQ_HEAD(, StatsCallbacks) stats_callbacks = QTAILQ_HEAD_INITIALIZER(stats_callbacks); void add_stats_callbacks(StatsProvider provider, StatRetrieveFunc *stats_fn, SchemaRetrieveFunc *schemas_fn) { StatsCallbacks *entry = g_new(StatsCallbacks, 1); entry->provider = provider; entry->stats_cb = stats_fn; entry->schemas_cb = schemas_fn; QTAILQ_INSERT_TAIL(&stats_callbacks, entry, next); } static bool invoke_stats_cb(StatsCallbacks *entry, StatsResultList **stats_results, StatsFilter *filter, StatsRequest *request, Error **errp) { ERRP_GUARD(); strList *targets = NULL; strList *names = NULL; if (request) { if (request->provider != entry->provider) { return true; } if (request->has_names && !request->names) { return true; } names = request->has_names ? request->names : NULL; } switch (filter->target) { case STATS_TARGET_VM: break; case STATS_TARGET_VCPU: if (filter->u.vcpu.has_vcpus) { if (!filter->u.vcpu.vcpus) { /* No targets allowed? Return no statistics. */ return true; } targets = filter->u.vcpu.vcpus; } break; default: abort(); } entry->stats_cb(stats_results, filter->target, names, targets, errp); if (*errp) { qapi_free_StatsResultList(*stats_results); *stats_results = NULL; return false; } return true; } StatsResultList *qmp_query_stats(StatsFilter *filter, Error **errp) { StatsResultList *stats_results = NULL; StatsCallbacks *entry; StatsRequestList *request; QTAILQ_FOREACH(entry, &stats_callbacks, next) { if (filter->has_providers) { for (request = filter->providers; request; request = request->next) { if (!invoke_stats_cb(entry, &stats_results, filter, request->value, errp)) { break; } } } else { if (!invoke_stats_cb(entry, &stats_results, filter, NULL, errp)) { break; } } } return stats_results; } StatsSchemaList *qmp_query_stats_schemas(bool has_provider, StatsProvider provider, Error **errp) { ERRP_GUARD(); StatsSchemaList *stats_results = NULL; StatsCallbacks *entry; QTAILQ_FOREACH(entry, &stats_callbacks, next) { if (!has_provider || provider == entry->provider) { entry->schemas_cb(&stats_results, errp); if (*errp) { qapi_free_StatsSchemaList(stats_results); return NULL; } } } return stats_results; } void add_stats_entry(StatsResultList **stats_results, StatsProvider provider, const char *qom_path, StatsList *stats_list) { StatsResult *entry = g_new0(StatsResult, 1); entry->provider = provider; entry->qom_path = g_strdup(qom_path); entry->stats = stats_list; QAPI_LIST_PREPEND(*stats_results, entry); } void add_stats_schema(StatsSchemaList **schema_results, StatsProvider provider, StatsTarget target, StatsSchemaValueList *stats_list) { StatsSchema *entry = g_new0(StatsSchema, 1); entry->provider = provider; entry->target = target; entry->stats = stats_list; QAPI_LIST_PREPEND(*schema_results, entry); } bool apply_str_list_filter(const char *string, strList *list) { strList *str_list = NULL; if (!list) { return true; } for (str_list = list; str_list; str_list = str_list->next) { if (g_str_equal(string, str_list->value)) { return true; } } return false; }