qemu/tests/qtest/libqos/qos_external.c
<<
>>
Prefs
   1/*
   2 * libqos driver framework
   3 *
   4 * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License version 2 as published by the Free Software Foundation.
   9 *
  10 * This library is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13 * Lesser General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU Lesser General Public
  16 * License along with this library; if not, see <http://www.gnu.org/licenses/>
  17 */
  18
  19#include "qemu/osdep.h"
  20#include <getopt.h>
  21#include "libqtest.h"
  22#include "qapi/qmp/qdict.h"
  23#include "qapi/qmp/qbool.h"
  24#include "qapi/qmp/qstring.h"
  25#include "qemu/module.h"
  26#include "qapi/qmp/qlist.h"
  27#include "libqos/malloc.h"
  28#include "libqos/qgraph.h"
  29#include "libqos/qgraph_internal.h"
  30#include "libqos/qos_external.h"
  31
  32
  33
  34void apply_to_node(const char *name, bool is_machine, bool is_abstract)
  35{
  36    char *machine_name = NULL;
  37    if (is_machine) {
  38        const char *arch = qtest_get_arch();
  39        machine_name = g_strconcat(arch, "/", name, NULL);
  40        name = machine_name;
  41    }
  42    qos_graph_node_set_availability(name, true);
  43    if (is_abstract) {
  44        qos_delete_cmd_line(name);
  45    }
  46    g_free(machine_name);
  47}
  48
  49/**
  50 * apply_to_qlist(): using QMP queries QEMU for a list of
  51 * machines and devices available, and sets the respective node
  52 * as true. If a node is found, also all its produced and contained
  53 * child are marked available.
  54 *
  55 * See qos_graph_node_set_availability() for more info
  56 */
  57void apply_to_qlist(QList *list, bool is_machine)
  58{
  59    const QListEntry *p;
  60    const char *name;
  61    bool abstract;
  62    QDict *minfo;
  63    QObject *qobj;
  64    QString *qstr;
  65    QBool *qbool;
  66
  67    for (p = qlist_first(list); p; p = qlist_next(p)) {
  68        minfo = qobject_to(QDict, qlist_entry_obj(p));
  69        qobj = qdict_get(minfo, "name");
  70        qstr = qobject_to(QString, qobj);
  71        name = qstring_get_str(qstr);
  72
  73        qobj = qdict_get(minfo, "abstract");
  74        if (qobj) {
  75            qbool = qobject_to(QBool, qobj);
  76            abstract = qbool_get_bool(qbool);
  77        } else {
  78            abstract = false;
  79        }
  80
  81        apply_to_node(name, is_machine, abstract);
  82        qobj = qdict_get(minfo, "alias");
  83        if (qobj) {
  84            qstr = qobject_to(QString, qobj);
  85            name = qstring_get_str(qstr);
  86            apply_to_node(name, is_machine, abstract);
  87        }
  88    }
  89}
  90
  91QGuestAllocator *get_machine_allocator(QOSGraphObject *obj)
  92{
  93    return obj->get_driver(obj, "memory");
  94}
  95
  96/**
  97 * allocate_objects(): given an array of nodes @arg,
  98 * walks the path invoking all constructors and
  99 * passing the corresponding parameter in order to
 100 * continue the objects allocation.
 101 * Once the test is reached, return the object it consumes.
 102 *
 103 * Since the machine and QEDGE_CONSUMED_BY nodes allocate
 104 * memory in the constructor, g_test_queue_destroy is used so
 105 * that after execution they can be safely free'd.  (The test's
 106 * ->before callback is also welcome to use g_test_queue_destroy).
 107 *
 108 * Note: as specified in walk_path() too, @arg is an array of
 109 * char *, where arg[0] is a pointer to the command line
 110 * string that will be used to properly start QEMU when executing
 111 * the test, and the remaining elements represent the actual objects
 112 * that will be allocated.
 113 */
 114void *allocate_objects(QTestState *qts, char **path, QGuestAllocator **p_alloc)
 115{
 116    int current = 0;
 117    QGuestAllocator *alloc;
 118    QOSGraphObject *parent = NULL;
 119    QOSGraphEdge *edge;
 120    QOSGraphNode *node;
 121    void *edge_arg;
 122    void *obj;
 123
 124    node = qos_graph_get_node(path[current]);
 125    g_assert(node->type == QNODE_MACHINE);
 126
 127    obj = qos_machine_new(node, qts);
 128    qos_object_queue_destroy(obj);
 129
 130    alloc = get_machine_allocator(obj);
 131    if (p_alloc) {
 132        *p_alloc = alloc;
 133    }
 134
 135    for (;;) {
 136        if (node->type != QNODE_INTERFACE) {
 137            qos_object_start_hw(obj);
 138            parent = obj;
 139        }
 140
 141        /* follow edge and get object for next node constructor */
 142        current++;
 143        edge = qos_graph_get_edge(path[current - 1], path[current]);
 144        node = qos_graph_get_node(path[current]);
 145
 146        if (node->type == QNODE_TEST) {
 147            g_assert(qos_graph_edge_get_type(edge) == QEDGE_CONSUMED_BY);
 148            return obj;
 149        }
 150
 151        switch (qos_graph_edge_get_type(edge)) {
 152        case QEDGE_PRODUCES:
 153            obj = parent->get_driver(parent, path[current]);
 154            break;
 155
 156        case QEDGE_CONSUMED_BY:
 157            edge_arg = qos_graph_edge_get_arg(edge);
 158            obj = qos_driver_new(node, obj, alloc, edge_arg);
 159            qos_object_queue_destroy(obj);
 160            break;
 161
 162        case QEDGE_CONTAINS:
 163            obj = parent->get_device(parent, path[current]);
 164            break;
 165        }
 166    }
 167}
 168
 169