11cf4323eSThomas Huth /*
21cf4323eSThomas Huth * libqos driver framework
31cf4323eSThomas Huth *
41cf4323eSThomas Huth * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
51cf4323eSThomas Huth *
61cf4323eSThomas Huth * This library is free software; you can redistribute it and/or
71cf4323eSThomas Huth * modify it under the terms of the GNU Lesser General Public
8dc0ad02dSThomas Huth * License version 2.1 as published by the Free Software Foundation.
91cf4323eSThomas Huth *
101cf4323eSThomas Huth * This library is distributed in the hope that it will be useful,
111cf4323eSThomas Huth * but WITHOUT ANY WARRANTY; without even the implied warranty of
121cf4323eSThomas Huth * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
131cf4323eSThomas Huth * Lesser General Public License for more details.
141cf4323eSThomas Huth *
151cf4323eSThomas Huth * You should have received a copy of the GNU Lesser General Public
161cf4323eSThomas Huth * License along with this library; if not, see <http://www.gnu.org/licenses/>
171cf4323eSThomas Huth */
181cf4323eSThomas Huth
191cf4323eSThomas Huth #include "qemu/osdep.h"
20907b5105SMarc-André Lureau #include "../libqtest.h"
211cf4323eSThomas Huth #include "qemu/queue.h"
22a2ce7dbdSPaolo Bonzini #include "qgraph_internal.h"
23a2ce7dbdSPaolo Bonzini #include "qgraph.h"
241cf4323eSThomas Huth
251cf4323eSThomas Huth #define QGRAPH_PRINT_DEBUG 0
261cf4323eSThomas Huth #define QOS_ROOT ""
271cf4323eSThomas Huth typedef struct QOSStackElement QOSStackElement;
281cf4323eSThomas Huth
291cf4323eSThomas Huth /* Graph Edge.*/
301cf4323eSThomas Huth struct QOSGraphEdge {
311cf4323eSThomas Huth QOSEdgeType type;
321cf4323eSThomas Huth char *dest;
331cf4323eSThomas Huth void *arg; /* just for QEDGE_CONTAINS
341cf4323eSThomas Huth * and QEDGE_CONSUMED_BY */
351cf4323eSThomas Huth char *extra_device_opts; /* added to -device option, "," is
361cf4323eSThomas Huth * automatically added
371cf4323eSThomas Huth */
381cf4323eSThomas Huth char *before_cmd_line; /* added before node cmd_line */
391cf4323eSThomas Huth char *after_cmd_line; /* added after -device options */
401cf4323eSThomas Huth char *edge_name; /* used by QEDGE_CONTAINS */
411cf4323eSThomas Huth QSLIST_ENTRY(QOSGraphEdge) edge_list;
421cf4323eSThomas Huth };
431cf4323eSThomas Huth
441cf4323eSThomas Huth typedef QSLIST_HEAD(, QOSGraphEdge) QOSGraphEdgeList;
451cf4323eSThomas Huth
461cf4323eSThomas Huth /**
471cf4323eSThomas Huth * Stack used to keep track of the discovered path when using
481cf4323eSThomas Huth * the DFS algorithm
491cf4323eSThomas Huth */
501cf4323eSThomas Huth struct QOSStackElement {
511cf4323eSThomas Huth QOSGraphNode *node;
521cf4323eSThomas Huth QOSStackElement *parent;
531cf4323eSThomas Huth QOSGraphEdge *parent_edge;
541cf4323eSThomas Huth int length;
551cf4323eSThomas Huth };
561cf4323eSThomas Huth
57*96420a30SMichael Tokarev /* Each entry in these hash table will consist of <string, node/edge> pair. */
581cf4323eSThomas Huth static GHashTable *edge_table;
591cf4323eSThomas Huth static GHashTable *node_table;
601cf4323eSThomas Huth
611cf4323eSThomas Huth /* stack used by the DFS algorithm to store the path from machine to test */
621cf4323eSThomas Huth static QOSStackElement qos_node_stack[QOS_PATH_MAX_ELEMENT_SIZE];
631cf4323eSThomas Huth static int qos_node_tos;
641cf4323eSThomas Huth
651cf4323eSThomas Huth /**
661cf4323eSThomas Huth * add_edge(): creates an edge of type @type
671cf4323eSThomas Huth * from @source to @dest node, and inserts it in the
681cf4323eSThomas Huth * edges hash table
691cf4323eSThomas Huth *
701cf4323eSThomas Huth * Nodes @source and @dest do not necessarily need to exist.
711cf4323eSThomas Huth * Possibility to add also options (see #QOSGraphEdgeOptions)
721cf4323eSThomas Huth * edge->edge_name is used as identifier for get_device relationships,
731cf4323eSThomas Huth * so by default is equal to @dest.
741cf4323eSThomas Huth */
add_edge(const char * source,const char * dest,QOSEdgeType type,QOSGraphEdgeOptions * opts)751cf4323eSThomas Huth static void add_edge(const char *source, const char *dest,
761cf4323eSThomas Huth QOSEdgeType type, QOSGraphEdgeOptions *opts)
771cf4323eSThomas Huth {
781cf4323eSThomas Huth char *key;
791cf4323eSThomas Huth QOSGraphEdgeList *list = g_hash_table_lookup(edge_table, source);
801cf4323eSThomas Huth QOSGraphEdgeOptions def_opts = { };
811cf4323eSThomas Huth
821cf4323eSThomas Huth if (!list) {
831cf4323eSThomas Huth list = g_new0(QOSGraphEdgeList, 1);
841cf4323eSThomas Huth key = g_strdup(source);
851cf4323eSThomas Huth g_hash_table_insert(edge_table, key, list);
861cf4323eSThomas Huth }
871cf4323eSThomas Huth
881cf4323eSThomas Huth if (!opts) {
891cf4323eSThomas Huth opts = &def_opts;
901cf4323eSThomas Huth }
911cf4323eSThomas Huth
921cf4323eSThomas Huth QOSGraphEdge *edge = g_new0(QOSGraphEdge, 1);
931cf4323eSThomas Huth edge->type = type;
941cf4323eSThomas Huth edge->dest = g_strdup(dest);
951cf4323eSThomas Huth edge->edge_name = g_strdup(opts->edge_name ?: dest);
96460056dbSPhilippe Mathieu-Daudé edge->arg = g_memdup2(opts->arg, opts->size_arg);
971cf4323eSThomas Huth
981cf4323eSThomas Huth edge->before_cmd_line =
991cf4323eSThomas Huth opts->before_cmd_line ? g_strconcat(" ", opts->before_cmd_line, NULL) : NULL;
1001cf4323eSThomas Huth edge->extra_device_opts =
1011cf4323eSThomas Huth opts->extra_device_opts ? g_strconcat(",", opts->extra_device_opts, NULL) : NULL;
1021cf4323eSThomas Huth edge->after_cmd_line =
1031cf4323eSThomas Huth opts->after_cmd_line ? g_strconcat(" ", opts->after_cmd_line, NULL) : NULL;
1041cf4323eSThomas Huth
1051cf4323eSThomas Huth QSLIST_INSERT_HEAD(list, edge, edge_list);
1061cf4323eSThomas Huth }
1071cf4323eSThomas Huth
1081cf4323eSThomas Huth /* destroy_edges(): frees all edges inside a given @list */
destroy_edges(void * list)1091cf4323eSThomas Huth static void destroy_edges(void *list)
1101cf4323eSThomas Huth {
1111cf4323eSThomas Huth QOSGraphEdge *temp;
1121cf4323eSThomas Huth QOSGraphEdgeList *elist = list;
1131cf4323eSThomas Huth
1141cf4323eSThomas Huth while (!QSLIST_EMPTY(elist)) {
1151cf4323eSThomas Huth temp = QSLIST_FIRST(elist);
1161cf4323eSThomas Huth QSLIST_REMOVE_HEAD(elist, edge_list);
1171cf4323eSThomas Huth g_free(temp->dest);
1181cf4323eSThomas Huth g_free(temp->before_cmd_line);
1191cf4323eSThomas Huth g_free(temp->after_cmd_line);
1201cf4323eSThomas Huth g_free(temp->extra_device_opts);
1211cf4323eSThomas Huth g_free(temp->edge_name);
1221cf4323eSThomas Huth g_free(temp->arg);
1231cf4323eSThomas Huth g_free(temp);
1241cf4323eSThomas Huth }
1251cf4323eSThomas Huth g_free(elist);
1261cf4323eSThomas Huth }
1271cf4323eSThomas Huth
1281cf4323eSThomas Huth /**
1291cf4323eSThomas Huth * create_node(): creates a node @name of type @type
1301cf4323eSThomas Huth * and inserts it to the nodes hash table.
1311cf4323eSThomas Huth * By default, node is not available.
1321cf4323eSThomas Huth */
create_node(const char * name,QOSNodeType type)1331cf4323eSThomas Huth static QOSGraphNode *create_node(const char *name, QOSNodeType type)
1341cf4323eSThomas Huth {
1351cf4323eSThomas Huth if (g_hash_table_lookup(node_table, name)) {
1361cf4323eSThomas Huth g_printerr("Node %s already created\n", name);
1371cf4323eSThomas Huth abort();
1381cf4323eSThomas Huth }
1391cf4323eSThomas Huth
1401cf4323eSThomas Huth QOSGraphNode *node = g_new0(QOSGraphNode, 1);
1411cf4323eSThomas Huth node->type = type;
1421cf4323eSThomas Huth node->available = false;
1431cf4323eSThomas Huth node->name = g_strdup(name);
1441cf4323eSThomas Huth g_hash_table_insert(node_table, node->name, node);
1451cf4323eSThomas Huth return node;
1461cf4323eSThomas Huth }
1471cf4323eSThomas Huth
1481cf4323eSThomas Huth /**
1491cf4323eSThomas Huth * destroy_node(): frees a node @val from the nodes hash table.
1501cf4323eSThomas Huth * Note that node->name is not free'd since it will represent the
1511cf4323eSThomas Huth * hash table key
1521cf4323eSThomas Huth */
destroy_node(void * val)1531cf4323eSThomas Huth static void destroy_node(void *val)
1541cf4323eSThomas Huth {
1551cf4323eSThomas Huth QOSGraphNode *node = val;
156f6a2c6eeSChristian Schoenebeck g_free(node->qemu_name);
1571cf4323eSThomas Huth g_free(node->command_line);
1581cf4323eSThomas Huth g_free(node);
1591cf4323eSThomas Huth }
1601cf4323eSThomas Huth
1611cf4323eSThomas Huth /**
1621cf4323eSThomas Huth * destroy_string(): frees @key from the nodes hash table.
1631cf4323eSThomas Huth * Actually frees the node->name
1641cf4323eSThomas Huth */
destroy_string(void * key)1651cf4323eSThomas Huth static void destroy_string(void *key)
1661cf4323eSThomas Huth {
1671cf4323eSThomas Huth g_free(key);
1681cf4323eSThomas Huth }
1691cf4323eSThomas Huth
1701cf4323eSThomas Huth /**
1711cf4323eSThomas Huth * search_node(): search for a node @key in the nodes hash table
1721cf4323eSThomas Huth * Returns the QOSGraphNode if found, #NULL otherwise
1731cf4323eSThomas Huth */
search_node(const char * key)1741cf4323eSThomas Huth static QOSGraphNode *search_node(const char *key)
1751cf4323eSThomas Huth {
1761cf4323eSThomas Huth return g_hash_table_lookup(node_table, key);
1771cf4323eSThomas Huth }
1781cf4323eSThomas Huth
1791cf4323eSThomas Huth /**
1801cf4323eSThomas Huth * get_edgelist(): returns the edge list (value) assigned to
1811cf4323eSThomas Huth * the @key in the edge hash table.
1821cf4323eSThomas Huth * This list will contain all edges with source equal to @key
1831cf4323eSThomas Huth *
1841cf4323eSThomas Huth * Returns: on success: the %QOSGraphEdgeList
1851cf4323eSThomas Huth * otherwise: abort()
1861cf4323eSThomas Huth */
get_edgelist(const char * key)1871cf4323eSThomas Huth static QOSGraphEdgeList *get_edgelist(const char *key)
1881cf4323eSThomas Huth {
1891cf4323eSThomas Huth return g_hash_table_lookup(edge_table, key);
1901cf4323eSThomas Huth }
1911cf4323eSThomas Huth
1921cf4323eSThomas Huth /**
1931cf4323eSThomas Huth * search_list_edges(): search for an edge with destination @dest
1941cf4323eSThomas Huth * in the given @edgelist.
1951cf4323eSThomas Huth *
1961cf4323eSThomas Huth * Returns: on success: the %QOSGraphEdge
1971cf4323eSThomas Huth * otherwise: #NULL
1981cf4323eSThomas Huth */
search_list_edges(QOSGraphEdgeList * edgelist,const char * dest)1991cf4323eSThomas Huth static QOSGraphEdge *search_list_edges(QOSGraphEdgeList *edgelist,
2001cf4323eSThomas Huth const char *dest)
2011cf4323eSThomas Huth {
2021cf4323eSThomas Huth QOSGraphEdge *tmp, *next;
2031cf4323eSThomas Huth if (!edgelist) {
2041cf4323eSThomas Huth return NULL;
2051cf4323eSThomas Huth }
2061cf4323eSThomas Huth QSLIST_FOREACH_SAFE(tmp, edgelist, edge_list, next) {
2071cf4323eSThomas Huth if (g_strcmp0(tmp->dest, dest) == 0) {
2081cf4323eSThomas Huth break;
2091cf4323eSThomas Huth }
2101cf4323eSThomas Huth }
2111cf4323eSThomas Huth return tmp;
2121cf4323eSThomas Huth }
2131cf4323eSThomas Huth
2141cf4323eSThomas Huth /**
2151cf4323eSThomas Huth * search_machine(): search for a machine @name in the node hash
2161cf4323eSThomas Huth * table. A machine is the child of the root node.
217*96420a30SMichael Tokarev * This function forces the research in the children of the root,
2181cf4323eSThomas Huth * to check the node is a proper machine
2191cf4323eSThomas Huth *
2201cf4323eSThomas Huth * Returns: on success: the %QOSGraphNode
2211cf4323eSThomas Huth * otherwise: #NULL
2221cf4323eSThomas Huth */
search_machine(const char * name)2231cf4323eSThomas Huth static QOSGraphNode *search_machine(const char *name)
2241cf4323eSThomas Huth {
2251cf4323eSThomas Huth QOSGraphNode *n;
2261cf4323eSThomas Huth QOSGraphEdgeList *root_list = get_edgelist(QOS_ROOT);
2271cf4323eSThomas Huth QOSGraphEdge *e = search_list_edges(root_list, name);
2281cf4323eSThomas Huth if (!e) {
2291cf4323eSThomas Huth return NULL;
2301cf4323eSThomas Huth }
2311cf4323eSThomas Huth n = search_node(e->dest);
2321cf4323eSThomas Huth if (n->type == QNODE_MACHINE) {
2331cf4323eSThomas Huth return n;
2341cf4323eSThomas Huth }
2351cf4323eSThomas Huth return NULL;
2361cf4323eSThomas Huth }
2371cf4323eSThomas Huth
2381cf4323eSThomas Huth /**
2391cf4323eSThomas Huth * create_interface(): checks if there is already
2401cf4323eSThomas Huth * a node @node in the node hash table, if not
2411cf4323eSThomas Huth * creates a node @node of type #QNODE_INTERFACE
2421cf4323eSThomas Huth * and inserts it. If there is one, check it's
2431cf4323eSThomas Huth * a #QNODE_INTERFACE and abort() if it's not.
2441cf4323eSThomas Huth */
create_interface(const char * node)2451cf4323eSThomas Huth static void create_interface(const char *node)
2461cf4323eSThomas Huth {
2471cf4323eSThomas Huth QOSGraphNode *interface;
2481cf4323eSThomas Huth interface = search_node(node);
2491cf4323eSThomas Huth if (!interface) {
2501cf4323eSThomas Huth create_node(node, QNODE_INTERFACE);
2511cf4323eSThomas Huth } else if (interface->type != QNODE_INTERFACE) {
2521cf4323eSThomas Huth fprintf(stderr, "Error: Node %s is not an interface\n", node);
2531cf4323eSThomas Huth abort();
2541cf4323eSThomas Huth }
2551cf4323eSThomas Huth }
2561cf4323eSThomas Huth
2571cf4323eSThomas Huth /**
2581cf4323eSThomas Huth * build_machine_cmd_line(): builds the command line for the machine
2591cf4323eSThomas Huth * @node. The node name must be a valid qemu identifier, since it
2601cf4323eSThomas Huth * will be used to build the command line.
2611cf4323eSThomas Huth *
2621cf4323eSThomas Huth * It is also possible to pass an optional @args that will be
2631cf4323eSThomas Huth * concatenated to the command line.
2641cf4323eSThomas Huth *
2651cf4323eSThomas Huth * For machines, prepend -M to the machine name. ", @rgs" is added
2661cf4323eSThomas Huth * after the -M <machine> command.
2671cf4323eSThomas Huth */
build_machine_cmd_line(QOSGraphNode * node,const char * args)2681cf4323eSThomas Huth static void build_machine_cmd_line(QOSGraphNode *node, const char *args)
2691cf4323eSThomas Huth {
2701cf4323eSThomas Huth char *machine = qos_get_machine_type(node->name);
2711cf4323eSThomas Huth if (args) {
2721cf4323eSThomas Huth node->command_line = g_strconcat("-M ", machine, ",", args, NULL);
2731cf4323eSThomas Huth } else {
2741cf4323eSThomas Huth node->command_line = g_strconcat("-M ", machine, " ", NULL);
2751cf4323eSThomas Huth }
2761cf4323eSThomas Huth }
2771cf4323eSThomas Huth
2781cf4323eSThomas Huth /**
2791cf4323eSThomas Huth * build_driver_cmd_line(): builds the command line for the driver
2801cf4323eSThomas Huth * @node. The node name must be a valid qemu identifier, since it
2811cf4323eSThomas Huth * will be used to build the command line.
2821cf4323eSThomas Huth *
2831cf4323eSThomas Huth * Driver do not need additional command line, since it will be
2841cf4323eSThomas Huth * provided by the edge options.
2851cf4323eSThomas Huth *
2861cf4323eSThomas Huth * For drivers, prepend -device to the node name.
2871cf4323eSThomas Huth */
build_driver_cmd_line(QOSGraphNode * node)2881cf4323eSThomas Huth static void build_driver_cmd_line(QOSGraphNode *node)
2891cf4323eSThomas Huth {
290f6a2c6eeSChristian Schoenebeck const char *name = node->qemu_name ?: node->name;
291f6a2c6eeSChristian Schoenebeck node->command_line = g_strconcat(" -device ", name, NULL);
2921cf4323eSThomas Huth }
2931cf4323eSThomas Huth
2941cf4323eSThomas Huth /* qos_print_cb(): callback prints all path found by the DFS algorithm. */
qos_print_cb(QOSGraphNode * path,int length)2951cf4323eSThomas Huth static void qos_print_cb(QOSGraphNode *path, int length)
2961cf4323eSThomas Huth {
2971cf4323eSThomas Huth #if QGRAPH_PRINT_DEBUG
2981cf4323eSThomas Huth printf("%d elements\n", length);
2991cf4323eSThomas Huth
3001cf4323eSThomas Huth if (!path) {
3011cf4323eSThomas Huth return;
3021cf4323eSThomas Huth }
3031cf4323eSThomas Huth
3041cf4323eSThomas Huth while (path->path_edge) {
3051cf4323eSThomas Huth printf("%s ", path->name);
3061cf4323eSThomas Huth switch (path->path_edge->type) {
3071cf4323eSThomas Huth case QEDGE_PRODUCES:
3081cf4323eSThomas Huth printf("--PRODUCES--> ");
3091cf4323eSThomas Huth break;
3101cf4323eSThomas Huth case QEDGE_CONSUMED_BY:
3111cf4323eSThomas Huth printf("--CONSUMED_BY--> ");
3121cf4323eSThomas Huth break;
3131cf4323eSThomas Huth case QEDGE_CONTAINS:
3141cf4323eSThomas Huth printf("--CONTAINS--> ");
3151cf4323eSThomas Huth break;
3161cf4323eSThomas Huth }
3171cf4323eSThomas Huth path = search_node(path->path_edge->dest);
3181cf4323eSThomas Huth }
3191cf4323eSThomas Huth
3201cf4323eSThomas Huth printf("%s\n\n", path->name);
3211cf4323eSThomas Huth #endif
3221cf4323eSThomas Huth }
3231cf4323eSThomas Huth
3241cf4323eSThomas Huth /* qos_push(): push a node @el and edge @e in the qos_node_stack */
qos_push(QOSGraphNode * el,QOSStackElement * parent,QOSGraphEdge * e)3251cf4323eSThomas Huth static void qos_push(QOSGraphNode *el, QOSStackElement *parent,
3261cf4323eSThomas Huth QOSGraphEdge *e)
3271cf4323eSThomas Huth {
3281cf4323eSThomas Huth int len = 0; /* root is not counted */
3291cf4323eSThomas Huth if (qos_node_tos == QOS_PATH_MAX_ELEMENT_SIZE) {
3301cf4323eSThomas Huth g_printerr("QOSStack: full stack, cannot push");
3311cf4323eSThomas Huth abort();
3321cf4323eSThomas Huth }
3331cf4323eSThomas Huth
3341cf4323eSThomas Huth if (parent) {
3351cf4323eSThomas Huth len = parent->length + 1;
3361cf4323eSThomas Huth }
3371cf4323eSThomas Huth qos_node_stack[qos_node_tos++] = (QOSStackElement) {
3381cf4323eSThomas Huth .node = el,
3391cf4323eSThomas Huth .parent = parent,
3401cf4323eSThomas Huth .parent_edge = e,
3411cf4323eSThomas Huth .length = len,
3421cf4323eSThomas Huth };
3431cf4323eSThomas Huth }
3441cf4323eSThomas Huth
3451cf4323eSThomas Huth /* qos_tos(): returns the top of stack, without popping */
qos_tos(void)3461cf4323eSThomas Huth static QOSStackElement *qos_tos(void)
3471cf4323eSThomas Huth {
3481cf4323eSThomas Huth return &qos_node_stack[qos_node_tos - 1];
3491cf4323eSThomas Huth }
3501cf4323eSThomas Huth
3511cf4323eSThomas Huth /* qos_pop(): pops an element from the tos, setting it unvisited*/
qos_pop(void)3521cf4323eSThomas Huth static QOSStackElement *qos_pop(void)
3531cf4323eSThomas Huth {
3541cf4323eSThomas Huth if (qos_node_tos == 0) {
3551cf4323eSThomas Huth g_printerr("QOSStack: empty stack, cannot pop");
3561cf4323eSThomas Huth abort();
3571cf4323eSThomas Huth }
3581cf4323eSThomas Huth QOSStackElement *e = qos_tos();
3591cf4323eSThomas Huth e->node->visited = false;
3601cf4323eSThomas Huth qos_node_tos--;
3611cf4323eSThomas Huth return e;
3621cf4323eSThomas Huth }
3631cf4323eSThomas Huth
3641cf4323eSThomas Huth /**
3651cf4323eSThomas Huth * qos_reverse_path(): reverses the found path, going from
3661cf4323eSThomas Huth * test-to-machine to machine-to-test
3671cf4323eSThomas Huth */
qos_reverse_path(QOSStackElement * el)3681cf4323eSThomas Huth static QOSGraphNode *qos_reverse_path(QOSStackElement *el)
3691cf4323eSThomas Huth {
3701cf4323eSThomas Huth if (!el) {
3711cf4323eSThomas Huth return NULL;
3721cf4323eSThomas Huth }
3731cf4323eSThomas Huth
3741cf4323eSThomas Huth el->node->path_edge = NULL;
3751cf4323eSThomas Huth
3761cf4323eSThomas Huth while (el->parent) {
3771cf4323eSThomas Huth el->parent->node->path_edge = el->parent_edge;
3781cf4323eSThomas Huth el = el->parent;
3791cf4323eSThomas Huth }
3801cf4323eSThomas Huth
3811cf4323eSThomas Huth return el->node;
3821cf4323eSThomas Huth }
3831cf4323eSThomas Huth
3841cf4323eSThomas Huth /**
3851cf4323eSThomas Huth * qos_traverse_graph(): graph-walking algorithm, using Depth First Search it
3861cf4323eSThomas Huth * starts from the root @machine and walks all possible path until it
3871cf4323eSThomas Huth * reaches a test node.
3881cf4323eSThomas Huth * At that point, it reverses the path found and invokes the @callback.
3891cf4323eSThomas Huth *
3901cf4323eSThomas Huth * Being Depth First Search, time complexity is O(|V| + |E|), while
3911cf4323eSThomas Huth * space is O(|V|). In this case, the maximum stack size is set by
3921cf4323eSThomas Huth * QOS_PATH_MAX_ELEMENT_SIZE.
3931cf4323eSThomas Huth */
qos_traverse_graph(QOSGraphNode * root,QOSTestCallback callback)3941cf4323eSThomas Huth static void qos_traverse_graph(QOSGraphNode *root, QOSTestCallback callback)
3951cf4323eSThomas Huth {
3961cf4323eSThomas Huth QOSGraphNode *v, *dest_node, *path;
3971cf4323eSThomas Huth QOSStackElement *s_el;
3981cf4323eSThomas Huth QOSGraphEdge *e, *next;
3991cf4323eSThomas Huth QOSGraphEdgeList *list;
4001cf4323eSThomas Huth
4011cf4323eSThomas Huth qos_push(root, NULL, NULL);
4021cf4323eSThomas Huth
4031cf4323eSThomas Huth while (qos_node_tos > 0) {
4041cf4323eSThomas Huth s_el = qos_tos();
4051cf4323eSThomas Huth v = s_el->node;
4061cf4323eSThomas Huth if (v->visited) {
4071cf4323eSThomas Huth qos_pop();
4081cf4323eSThomas Huth continue;
4091cf4323eSThomas Huth }
4101cf4323eSThomas Huth v->visited = true;
4111cf4323eSThomas Huth list = get_edgelist(v->name);
4121cf4323eSThomas Huth if (!list) {
4131cf4323eSThomas Huth qos_pop();
4141cf4323eSThomas Huth if (v->type == QNODE_TEST) {
4151cf4323eSThomas Huth v->visited = false;
4161cf4323eSThomas Huth path = qos_reverse_path(s_el);
4171cf4323eSThomas Huth callback(path, s_el->length);
4181cf4323eSThomas Huth }
4191cf4323eSThomas Huth } else {
4201cf4323eSThomas Huth QSLIST_FOREACH_SAFE(e, list, edge_list, next) {
4211cf4323eSThomas Huth dest_node = search_node(e->dest);
4221cf4323eSThomas Huth
4231cf4323eSThomas Huth if (!dest_node) {
4241cf4323eSThomas Huth fprintf(stderr, "node %s in %s -> %s does not exist\n",
4251cf4323eSThomas Huth e->dest, v->name, e->dest);
4261cf4323eSThomas Huth abort();
4271cf4323eSThomas Huth }
4281cf4323eSThomas Huth
4291cf4323eSThomas Huth if (!dest_node->visited && dest_node->available) {
4301cf4323eSThomas Huth qos_push(dest_node, s_el, e);
4311cf4323eSThomas Huth }
4321cf4323eSThomas Huth }
4331cf4323eSThomas Huth }
4341cf4323eSThomas Huth }
4351cf4323eSThomas Huth }
4361cf4323eSThomas Huth
4371cf4323eSThomas Huth /* QGRAPH API*/
4381cf4323eSThomas Huth
qos_graph_get_node(const char * key)4391cf4323eSThomas Huth QOSGraphNode *qos_graph_get_node(const char *key)
4401cf4323eSThomas Huth {
4411cf4323eSThomas Huth return search_node(key);
4421cf4323eSThomas Huth }
4431cf4323eSThomas Huth
qos_graph_has_node(const char * node)4441cf4323eSThomas Huth bool qos_graph_has_node(const char *node)
4451cf4323eSThomas Huth {
4461cf4323eSThomas Huth QOSGraphNode *n = search_node(node);
4471cf4323eSThomas Huth return n != NULL;
4481cf4323eSThomas Huth }
4491cf4323eSThomas Huth
qos_graph_get_node_type(const char * node)4501cf4323eSThomas Huth QOSNodeType qos_graph_get_node_type(const char *node)
4511cf4323eSThomas Huth {
4521cf4323eSThomas Huth QOSGraphNode *n = search_node(node);
4531cf4323eSThomas Huth if (n) {
4541cf4323eSThomas Huth return n->type;
4551cf4323eSThomas Huth }
4561cf4323eSThomas Huth return -1;
4571cf4323eSThomas Huth }
4581cf4323eSThomas Huth
qos_graph_get_node_availability(const char * node)4591cf4323eSThomas Huth bool qos_graph_get_node_availability(const char *node)
4601cf4323eSThomas Huth {
4611cf4323eSThomas Huth QOSGraphNode *n = search_node(node);
4621cf4323eSThomas Huth if (n) {
4631cf4323eSThomas Huth return n->available;
4641cf4323eSThomas Huth }
4651cf4323eSThomas Huth return false;
4661cf4323eSThomas Huth }
4671cf4323eSThomas Huth
qos_graph_get_edge(const char * node,const char * dest)4681cf4323eSThomas Huth QOSGraphEdge *qos_graph_get_edge(const char *node, const char *dest)
4691cf4323eSThomas Huth {
4701cf4323eSThomas Huth QOSGraphEdgeList *list = get_edgelist(node);
4711cf4323eSThomas Huth return search_list_edges(list, dest);
4721cf4323eSThomas Huth }
4731cf4323eSThomas Huth
qos_graph_edge_get_type(QOSGraphEdge * edge)4741cf4323eSThomas Huth QOSEdgeType qos_graph_edge_get_type(QOSGraphEdge *edge)
4751cf4323eSThomas Huth {
4761cf4323eSThomas Huth if (!edge) {
4771cf4323eSThomas Huth return -1;
4781cf4323eSThomas Huth }
47958bcdda9SPhilippe Mathieu-Daudé return edge->type;
4801cf4323eSThomas Huth }
4811cf4323eSThomas Huth
qos_graph_edge_get_dest(QOSGraphEdge * edge)4821cf4323eSThomas Huth char *qos_graph_edge_get_dest(QOSGraphEdge *edge)
4831cf4323eSThomas Huth {
4841cf4323eSThomas Huth if (!edge) {
4851cf4323eSThomas Huth return NULL;
4861cf4323eSThomas Huth }
4871cf4323eSThomas Huth return edge->dest;
4881cf4323eSThomas Huth }
4891cf4323eSThomas Huth
qos_graph_edge_get_arg(QOSGraphEdge * edge)4901cf4323eSThomas Huth void *qos_graph_edge_get_arg(QOSGraphEdge *edge)
4911cf4323eSThomas Huth {
4921cf4323eSThomas Huth if (!edge) {
4931cf4323eSThomas Huth return NULL;
4941cf4323eSThomas Huth }
4951cf4323eSThomas Huth return edge->arg;
4961cf4323eSThomas Huth }
4971cf4323eSThomas Huth
qos_graph_edge_get_after_cmd_line(QOSGraphEdge * edge)4981cf4323eSThomas Huth char *qos_graph_edge_get_after_cmd_line(QOSGraphEdge *edge)
4991cf4323eSThomas Huth {
5001cf4323eSThomas Huth if (!edge) {
5011cf4323eSThomas Huth return NULL;
5021cf4323eSThomas Huth }
5031cf4323eSThomas Huth return edge->after_cmd_line;
5041cf4323eSThomas Huth }
5051cf4323eSThomas Huth
qos_graph_edge_get_before_cmd_line(QOSGraphEdge * edge)5061cf4323eSThomas Huth char *qos_graph_edge_get_before_cmd_line(QOSGraphEdge *edge)
5071cf4323eSThomas Huth {
5081cf4323eSThomas Huth if (!edge) {
5091cf4323eSThomas Huth return NULL;
5101cf4323eSThomas Huth }
5111cf4323eSThomas Huth return edge->before_cmd_line;
5121cf4323eSThomas Huth }
5131cf4323eSThomas Huth
qos_graph_edge_get_extra_device_opts(QOSGraphEdge * edge)5141cf4323eSThomas Huth char *qos_graph_edge_get_extra_device_opts(QOSGraphEdge *edge)
5151cf4323eSThomas Huth {
5161cf4323eSThomas Huth if (!edge) {
5171cf4323eSThomas Huth return NULL;
5181cf4323eSThomas Huth }
5191cf4323eSThomas Huth return edge->extra_device_opts;
5201cf4323eSThomas Huth }
5211cf4323eSThomas Huth
qos_graph_edge_get_name(QOSGraphEdge * edge)5221cf4323eSThomas Huth char *qos_graph_edge_get_name(QOSGraphEdge *edge)
5231cf4323eSThomas Huth {
5241cf4323eSThomas Huth if (!edge) {
5251cf4323eSThomas Huth return NULL;
5261cf4323eSThomas Huth }
5271cf4323eSThomas Huth return edge->edge_name;
5281cf4323eSThomas Huth }
5291cf4323eSThomas Huth
qos_graph_has_edge(const char * start,const char * dest)5301cf4323eSThomas Huth bool qos_graph_has_edge(const char *start, const char *dest)
5311cf4323eSThomas Huth {
5321cf4323eSThomas Huth QOSGraphEdgeList *list = get_edgelist(start);
5331cf4323eSThomas Huth QOSGraphEdge *e = search_list_edges(list, dest);
5341cf4323eSThomas Huth return e != NULL;
5351cf4323eSThomas Huth }
5361cf4323eSThomas Huth
qos_graph_get_machine(const char * node)5371cf4323eSThomas Huth QOSGraphNode *qos_graph_get_machine(const char *node)
5381cf4323eSThomas Huth {
5391cf4323eSThomas Huth return search_machine(node);
5401cf4323eSThomas Huth }
5411cf4323eSThomas Huth
qos_graph_has_machine(const char * node)5421cf4323eSThomas Huth bool qos_graph_has_machine(const char *node)
5431cf4323eSThomas Huth {
5441cf4323eSThomas Huth QOSGraphNode *m = search_machine(node);
5451cf4323eSThomas Huth return m != NULL;
5461cf4323eSThomas Huth }
5471cf4323eSThomas Huth
qos_print_graph(void)5481cf4323eSThomas Huth void qos_print_graph(void)
5491cf4323eSThomas Huth {
5501cf4323eSThomas Huth qos_graph_foreach_test_path(qos_print_cb);
5511cf4323eSThomas Huth }
5521cf4323eSThomas Huth
qos_graph_init(void)5531cf4323eSThomas Huth void qos_graph_init(void)
5541cf4323eSThomas Huth {
5551cf4323eSThomas Huth if (!node_table) {
5561cf4323eSThomas Huth node_table = g_hash_table_new_full(g_str_hash, g_str_equal,
5571cf4323eSThomas Huth destroy_string, destroy_node);
5581cf4323eSThomas Huth create_node(QOS_ROOT, QNODE_DRIVER);
5591cf4323eSThomas Huth }
5601cf4323eSThomas Huth
5611cf4323eSThomas Huth if (!edge_table) {
5621cf4323eSThomas Huth edge_table = g_hash_table_new_full(g_str_hash, g_str_equal,
5631cf4323eSThomas Huth destroy_string, destroy_edges);
5641cf4323eSThomas Huth }
5651cf4323eSThomas Huth }
5661cf4323eSThomas Huth
qos_graph_destroy(void)5671cf4323eSThomas Huth void qos_graph_destroy(void)
5681cf4323eSThomas Huth {
5691cf4323eSThomas Huth if (node_table) {
5701cf4323eSThomas Huth g_hash_table_destroy(node_table);
5711cf4323eSThomas Huth }
5721cf4323eSThomas Huth
5731cf4323eSThomas Huth if (edge_table) {
5741cf4323eSThomas Huth g_hash_table_destroy(edge_table);
5751cf4323eSThomas Huth }
5761cf4323eSThomas Huth
5771cf4323eSThomas Huth node_table = NULL;
5781cf4323eSThomas Huth edge_table = NULL;
5791cf4323eSThomas Huth }
5801cf4323eSThomas Huth
qos_node_destroy(void * key)5811cf4323eSThomas Huth void qos_node_destroy(void *key)
5821cf4323eSThomas Huth {
5831cf4323eSThomas Huth g_hash_table_remove(node_table, key);
5841cf4323eSThomas Huth }
5851cf4323eSThomas Huth
qos_edge_destroy(void * key)5861cf4323eSThomas Huth void qos_edge_destroy(void *key)
5871cf4323eSThomas Huth {
5881cf4323eSThomas Huth g_hash_table_remove(edge_table, key);
5891cf4323eSThomas Huth }
5901cf4323eSThomas Huth
qos_add_test(const char * name,const char * interface,QOSTestFunc test_func,QOSGraphTestOptions * opts)5911cf4323eSThomas Huth void qos_add_test(const char *name, const char *interface,
5921cf4323eSThomas Huth QOSTestFunc test_func, QOSGraphTestOptions *opts)
5931cf4323eSThomas Huth {
5941cf4323eSThomas Huth QOSGraphNode *node;
59558bcdda9SPhilippe Mathieu-Daudé char *test_name = g_strdup_printf("%s-tests/%s", interface, name);
5961cf4323eSThomas Huth QOSGraphTestOptions def_opts = { };
5971cf4323eSThomas Huth
5981cf4323eSThomas Huth if (!opts) {
5991cf4323eSThomas Huth opts = &def_opts;
6001cf4323eSThomas Huth }
6011cf4323eSThomas Huth node = create_node(test_name, QNODE_TEST);
6021cf4323eSThomas Huth node->u.test.function = test_func;
6031cf4323eSThomas Huth node->u.test.arg = opts->arg;
6041cf4323eSThomas Huth assert(!opts->edge.arg);
6051cf4323eSThomas Huth assert(!opts->edge.size_arg);
6061cf4323eSThomas Huth
6071cf4323eSThomas Huth node->u.test.before = opts->before;
6081cf4323eSThomas Huth node->u.test.subprocess = opts->subprocess;
6091cf4323eSThomas Huth node->available = true;
6101cf4323eSThomas Huth add_edge(interface, test_name, QEDGE_CONSUMED_BY, &opts->edge);
6111cf4323eSThomas Huth g_free(test_name);
6121cf4323eSThomas Huth }
6131cf4323eSThomas Huth
qos_node_create_machine(const char * name,QOSCreateMachineFunc function)6141cf4323eSThomas Huth void qos_node_create_machine(const char *name, QOSCreateMachineFunc function)
6151cf4323eSThomas Huth {
6161cf4323eSThomas Huth qos_node_create_machine_args(name, function, NULL);
6171cf4323eSThomas Huth }
6181cf4323eSThomas Huth
qos_node_create_machine_args(const char * name,QOSCreateMachineFunc function,const char * opts)6191cf4323eSThomas Huth void qos_node_create_machine_args(const char *name,
6201cf4323eSThomas Huth QOSCreateMachineFunc function,
6211cf4323eSThomas Huth const char *opts)
6221cf4323eSThomas Huth {
6231cf4323eSThomas Huth QOSGraphNode *node = create_node(name, QNODE_MACHINE);
6241cf4323eSThomas Huth build_machine_cmd_line(node, opts);
6251cf4323eSThomas Huth node->u.machine.constructor = function;
6261cf4323eSThomas Huth add_edge(QOS_ROOT, name, QEDGE_CONTAINS, NULL);
6271cf4323eSThomas Huth }
6281cf4323eSThomas Huth
qos_node_create_driver(const char * name,QOSCreateDriverFunc function)6291cf4323eSThomas Huth void qos_node_create_driver(const char *name, QOSCreateDriverFunc function)
6301cf4323eSThomas Huth {
6311cf4323eSThomas Huth QOSGraphNode *node = create_node(name, QNODE_DRIVER);
6321cf4323eSThomas Huth build_driver_cmd_line(node);
6331cf4323eSThomas Huth node->u.driver.constructor = function;
6341cf4323eSThomas Huth }
6351cf4323eSThomas Huth
qos_node_create_driver_named(const char * name,const char * qemu_name,QOSCreateDriverFunc function)636f6a2c6eeSChristian Schoenebeck void qos_node_create_driver_named(const char *name, const char *qemu_name,
637f6a2c6eeSChristian Schoenebeck QOSCreateDriverFunc function)
638f6a2c6eeSChristian Schoenebeck {
639f6a2c6eeSChristian Schoenebeck QOSGraphNode *node = create_node(name, QNODE_DRIVER);
640f6a2c6eeSChristian Schoenebeck node->qemu_name = g_strdup(qemu_name);
641f6a2c6eeSChristian Schoenebeck build_driver_cmd_line(node);
642f6a2c6eeSChristian Schoenebeck node->u.driver.constructor = function;
643f6a2c6eeSChristian Schoenebeck }
644f6a2c6eeSChristian Schoenebeck
qos_node_contains(const char * container,const char * contained,QOSGraphEdgeOptions * opts,...)6451cf4323eSThomas Huth void qos_node_contains(const char *container, const char *contained,
6461cf4323eSThomas Huth QOSGraphEdgeOptions *opts, ...)
6471cf4323eSThomas Huth {
6481cf4323eSThomas Huth va_list va;
6491cf4323eSThomas Huth
6501cf4323eSThomas Huth if (opts == NULL) {
6511cf4323eSThomas Huth add_edge(container, contained, QEDGE_CONTAINS, NULL);
6521cf4323eSThomas Huth return;
6531cf4323eSThomas Huth }
6541cf4323eSThomas Huth
6551cf4323eSThomas Huth va_start(va, opts);
6561cf4323eSThomas Huth do {
6571cf4323eSThomas Huth add_edge(container, contained, QEDGE_CONTAINS, opts);
6581cf4323eSThomas Huth opts = va_arg(va, QOSGraphEdgeOptions *);
6591cf4323eSThomas Huth } while (opts != NULL);
6601cf4323eSThomas Huth
6611cf4323eSThomas Huth va_end(va);
6621cf4323eSThomas Huth }
6631cf4323eSThomas Huth
qos_node_produces(const char * producer,const char * interface)6641cf4323eSThomas Huth void qos_node_produces(const char *producer, const char *interface)
6651cf4323eSThomas Huth {
6661cf4323eSThomas Huth create_interface(interface);
6671cf4323eSThomas Huth add_edge(producer, interface, QEDGE_PRODUCES, NULL);
6681cf4323eSThomas Huth }
6691cf4323eSThomas Huth
qos_node_consumes(const char * consumer,const char * interface,QOSGraphEdgeOptions * opts)6701cf4323eSThomas Huth void qos_node_consumes(const char *consumer, const char *interface,
6711cf4323eSThomas Huth QOSGraphEdgeOptions *opts)
6721cf4323eSThomas Huth {
6731cf4323eSThomas Huth create_interface(interface);
6741cf4323eSThomas Huth add_edge(interface, consumer, QEDGE_CONSUMED_BY, opts);
6751cf4323eSThomas Huth }
6761cf4323eSThomas Huth
qos_graph_node_set_availability_explicit(const char * node,bool av)677f6a2c6eeSChristian Schoenebeck static void qos_graph_node_set_availability_explicit(const char *node, bool av)
6781cf4323eSThomas Huth {
6791cf4323eSThomas Huth QOSGraphEdgeList *elist;
6801cf4323eSThomas Huth QOSGraphNode *n = search_node(node);
6811cf4323eSThomas Huth QOSGraphEdge *e, *next;
6821cf4323eSThomas Huth if (!n) {
6831cf4323eSThomas Huth return;
6841cf4323eSThomas Huth }
6851cf4323eSThomas Huth n->available = av;
6861cf4323eSThomas Huth elist = get_edgelist(node);
6871cf4323eSThomas Huth if (!elist) {
6881cf4323eSThomas Huth return;
6891cf4323eSThomas Huth }
6901cf4323eSThomas Huth QSLIST_FOREACH_SAFE(e, elist, edge_list, next) {
6911cf4323eSThomas Huth if (e->type == QEDGE_CONTAINS || e->type == QEDGE_PRODUCES) {
692f6a2c6eeSChristian Schoenebeck qos_graph_node_set_availability_explicit(e->dest, av);
6931cf4323eSThomas Huth }
6941cf4323eSThomas Huth }
6951cf4323eSThomas Huth }
6961cf4323eSThomas Huth
697f6a2c6eeSChristian Schoenebeck /*
698f6a2c6eeSChristian Schoenebeck * Behaves as qos_graph_node_set_availability_explicit(), except that the
699f6a2c6eeSChristian Schoenebeck * former always matches by node name only, whereas this function matches both
700f6a2c6eeSChristian Schoenebeck * by node name and node's optional 'qemu_name' field.
701f6a2c6eeSChristian Schoenebeck */
qos_graph_node_set_availability(const char * node,bool av)702f6a2c6eeSChristian Schoenebeck void qos_graph_node_set_availability(const char *node, bool av)
703f6a2c6eeSChristian Schoenebeck {
704f6a2c6eeSChristian Schoenebeck GList *l;
705f6a2c6eeSChristian Schoenebeck QOSGraphEdgeList *elist;
706f6a2c6eeSChristian Schoenebeck QOSGraphEdge *e, *next;
707f6a2c6eeSChristian Schoenebeck QOSGraphNode *n;
708f6a2c6eeSChristian Schoenebeck GList *keys = g_hash_table_get_keys(node_table);
709f6a2c6eeSChristian Schoenebeck
710f6a2c6eeSChristian Schoenebeck for (l = keys; l != NULL; l = l->next) {
711f6a2c6eeSChristian Schoenebeck const gchar *key = l->data;
712f6a2c6eeSChristian Schoenebeck n = g_hash_table_lookup(node_table, key);
713f6a2c6eeSChristian Schoenebeck /*
714f6a2c6eeSChristian Schoenebeck * node's 'qemu_name' is set if there is more than one device with
715f6a2c6eeSChristian Schoenebeck * the same QEMU (QMP) device name
716f6a2c6eeSChristian Schoenebeck */
717f6a2c6eeSChristian Schoenebeck const char *node_name = n->qemu_name ?: n->name;
718f6a2c6eeSChristian Schoenebeck if (g_strcmp0(node_name, node) == 0) {
719f6a2c6eeSChristian Schoenebeck n->available = av;
720f6a2c6eeSChristian Schoenebeck elist = get_edgelist(n->name);
721f6a2c6eeSChristian Schoenebeck if (elist) {
722f6a2c6eeSChristian Schoenebeck QSLIST_FOREACH_SAFE(e, elist, edge_list, next) {
723f6a2c6eeSChristian Schoenebeck if (e->type == QEDGE_CONTAINS || e->type == QEDGE_PRODUCES)
724f6a2c6eeSChristian Schoenebeck {
725f6a2c6eeSChristian Schoenebeck qos_graph_node_set_availability_explicit(e->dest, av);
726f6a2c6eeSChristian Schoenebeck }
727f6a2c6eeSChristian Schoenebeck }
728f6a2c6eeSChristian Schoenebeck }
729f6a2c6eeSChristian Schoenebeck }
730f6a2c6eeSChristian Schoenebeck }
731f6a2c6eeSChristian Schoenebeck g_list_free(keys);
732f6a2c6eeSChristian Schoenebeck }
733f6a2c6eeSChristian Schoenebeck
qos_graph_foreach_test_path(QOSTestCallback fn)7341cf4323eSThomas Huth void qos_graph_foreach_test_path(QOSTestCallback fn)
7351cf4323eSThomas Huth {
7361cf4323eSThomas Huth QOSGraphNode *root = qos_graph_get_node(QOS_ROOT);
7371cf4323eSThomas Huth qos_traverse_graph(root, fn);
7381cf4323eSThomas Huth }
7391cf4323eSThomas Huth
qos_machine_new(QOSGraphNode * node,QTestState * qts)7401cf4323eSThomas Huth QOSGraphObject *qos_machine_new(QOSGraphNode *node, QTestState *qts)
7411cf4323eSThomas Huth {
7421cf4323eSThomas Huth QOSGraphObject *obj;
7431cf4323eSThomas Huth
7441cf4323eSThomas Huth g_assert(node->type == QNODE_MACHINE);
7451cf4323eSThomas Huth obj = node->u.machine.constructor(qts);
7461cf4323eSThomas Huth obj->free = g_free;
7471cf4323eSThomas Huth return obj;
7481cf4323eSThomas Huth }
7491cf4323eSThomas Huth
qos_driver_new(QOSGraphNode * node,QOSGraphObject * parent,QGuestAllocator * alloc,void * arg)7501cf4323eSThomas Huth QOSGraphObject *qos_driver_new(QOSGraphNode *node, QOSGraphObject *parent,
7511cf4323eSThomas Huth QGuestAllocator *alloc, void *arg)
7521cf4323eSThomas Huth {
7531cf4323eSThomas Huth QOSGraphObject *obj;
7541cf4323eSThomas Huth
7551cf4323eSThomas Huth g_assert(node->type == QNODE_DRIVER);
7561cf4323eSThomas Huth obj = node->u.driver.constructor(parent, alloc, arg);
7571cf4323eSThomas Huth obj->free = g_free;
7581cf4323eSThomas Huth return obj;
7591cf4323eSThomas Huth }
7601cf4323eSThomas Huth
qos_object_destroy(QOSGraphObject * obj)7611cf4323eSThomas Huth void qos_object_destroy(QOSGraphObject *obj)
7621cf4323eSThomas Huth {
7631cf4323eSThomas Huth if (!obj) {
7641cf4323eSThomas Huth return;
7651cf4323eSThomas Huth }
7661cf4323eSThomas Huth if (obj->destructor) {
7671cf4323eSThomas Huth obj->destructor(obj);
7681cf4323eSThomas Huth }
7691cf4323eSThomas Huth if (obj->free) {
7701cf4323eSThomas Huth obj->free(obj);
7711cf4323eSThomas Huth }
7721cf4323eSThomas Huth }
7731cf4323eSThomas Huth
qos_object_queue_destroy(QOSGraphObject * obj)7741cf4323eSThomas Huth void qos_object_queue_destroy(QOSGraphObject *obj)
7751cf4323eSThomas Huth {
7761cf4323eSThomas Huth g_test_queue_destroy((GDestroyNotify) qos_object_destroy, obj);
7771cf4323eSThomas Huth }
7781cf4323eSThomas Huth
qos_object_start_hw(QOSGraphObject * obj)7791cf4323eSThomas Huth void qos_object_start_hw(QOSGraphObject *obj)
7801cf4323eSThomas Huth {
7811cf4323eSThomas Huth if (obj->start_hw) {
7821cf4323eSThomas Huth obj->start_hw(obj);
7831cf4323eSThomas Huth }
7841cf4323eSThomas Huth }
7851cf4323eSThomas Huth
qos_get_machine_type(char * name)7861cf4323eSThomas Huth char *qos_get_machine_type(char *name)
7871cf4323eSThomas Huth {
7881cf4323eSThomas Huth while (*name != '\0' && *name != '/') {
7891cf4323eSThomas Huth name++;
7901cf4323eSThomas Huth }
7911cf4323eSThomas Huth
7921cf4323eSThomas Huth if (!*name || !name[1]) {
7931cf4323eSThomas Huth fprintf(stderr, "Machine name has to be of the form <arch>/<machine>\n");
7941cf4323eSThomas Huth abort();
7951cf4323eSThomas Huth }
7961cf4323eSThomas Huth
7971cf4323eSThomas Huth return name + 1;
7981cf4323eSThomas Huth }
7991cf4323eSThomas Huth
qos_delete_cmd_line(const char * name)8001cf4323eSThomas Huth void qos_delete_cmd_line(const char *name)
8011cf4323eSThomas Huth {
8021cf4323eSThomas Huth QOSGraphNode *node = search_node(name);
8031cf4323eSThomas Huth if (node) {
8041cf4323eSThomas Huth g_free(node->command_line);
8051cf4323eSThomas Huth node->command_line = NULL;
8061cf4323eSThomas Huth }
8071cf4323eSThomas Huth }
80883ff78e5SChristian Schoenebeck
qos_dump_graph(void)80983ff78e5SChristian Schoenebeck void qos_dump_graph(void)
81083ff78e5SChristian Schoenebeck {
81183ff78e5SChristian Schoenebeck GList *keys;
81283ff78e5SChristian Schoenebeck GList *l;
81383ff78e5SChristian Schoenebeck QOSGraphEdgeList *list;
81483ff78e5SChristian Schoenebeck QOSGraphEdge *e, *next;
81583ff78e5SChristian Schoenebeck QOSGraphNode *dest_node, *node;
81683ff78e5SChristian Schoenebeck
81783ff78e5SChristian Schoenebeck qos_printf("ALL QGRAPH EDGES: {\n");
81883ff78e5SChristian Schoenebeck keys = g_hash_table_get_keys(edge_table);
81983ff78e5SChristian Schoenebeck for (l = keys; l != NULL; l = l->next) {
82083ff78e5SChristian Schoenebeck const gchar *key = l->data;
82183ff78e5SChristian Schoenebeck qos_printf("\t src='%s'\n", key);
82283ff78e5SChristian Schoenebeck list = get_edgelist(key);
82383ff78e5SChristian Schoenebeck QSLIST_FOREACH_SAFE(e, list, edge_list, next) {
82483ff78e5SChristian Schoenebeck dest_node = g_hash_table_lookup(node_table, e->dest);
82583ff78e5SChristian Schoenebeck qos_printf("\t\t|-> dest='%s' type=%d (node=%p)",
82683ff78e5SChristian Schoenebeck e->dest, e->type, dest_node);
82783ff78e5SChristian Schoenebeck if (!dest_node) {
82883ff78e5SChristian Schoenebeck qos_printf_literal(" <------- ERROR !");
82983ff78e5SChristian Schoenebeck }
83083ff78e5SChristian Schoenebeck qos_printf_literal("\n");
83183ff78e5SChristian Schoenebeck }
83283ff78e5SChristian Schoenebeck }
83383ff78e5SChristian Schoenebeck g_list_free(keys);
83483ff78e5SChristian Schoenebeck qos_printf("}\n");
83583ff78e5SChristian Schoenebeck
83683ff78e5SChristian Schoenebeck qos_printf("ALL QGRAPH NODES: {\n");
83783ff78e5SChristian Schoenebeck keys = g_hash_table_get_keys(node_table);
83883ff78e5SChristian Schoenebeck for (l = keys; l != NULL; l = l->next) {
83983ff78e5SChristian Schoenebeck const gchar *key = l->data;
84083ff78e5SChristian Schoenebeck node = g_hash_table_lookup(node_table, key);
84183ff78e5SChristian Schoenebeck qos_printf("\t name='%s' ", key);
84283ff78e5SChristian Schoenebeck if (node->qemu_name) {
84383ff78e5SChristian Schoenebeck qos_printf_literal("qemu_name='%s' ", node->qemu_name);
84483ff78e5SChristian Schoenebeck }
84583ff78e5SChristian Schoenebeck qos_printf_literal("type=%d cmd_line='%s' [%s]\n",
84683ff78e5SChristian Schoenebeck node->type, node->command_line,
847f6221529SStefan Hajnoczi node->available ? "available" : "UNAVAILABLE"
84883ff78e5SChristian Schoenebeck );
84983ff78e5SChristian Schoenebeck }
85083ff78e5SChristian Schoenebeck g_list_free(keys);
85183ff78e5SChristian Schoenebeck qos_printf("}\n");
85283ff78e5SChristian Schoenebeck }
853