2016-12-18 22:56:58 +00:00
|
|
|
/*
|
|
|
|
glib_compat.h replacement functionality for glib code used in qemu
|
|
|
|
Copyright (C) 2016 Chris Eagle cseagle at gmail dot com
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
2018-02-26 04:12:20 +00:00
|
|
|
#ifndef QEMU_GLIB_COMPAT_H
|
|
|
|
#define QEMU_GLIB_COMPAT_H
|
2016-12-18 22:56:58 +00:00
|
|
|
|
2017-01-20 13:13:21 +00:00
|
|
|
#include "unicorn/platform.h"
|
2016-12-18 22:56:58 +00:00
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#ifndef TRUE
|
|
|
|
#define TRUE 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef FALSE
|
2016-12-26 14:02:34 +00:00
|
|
|
#define FALSE 0
|
2016-12-18 22:56:58 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#define g_assert(expr) assert(expr)
|
|
|
|
#define g_assert_not_reached() assert(0)
|
|
|
|
|
2018-03-13 17:39:46 +00:00
|
|
|
#define g_assert_cmpstr(s1, cmp, s2) do { const char *__s1 = (s1), *__s2 = (s2); \
|
|
|
|
if (strcmp (__s1, __s2) cmp 0) ; else \
|
|
|
|
assert(false); \
|
|
|
|
} while (0)
|
|
|
|
#define g_assert_cmpint(n1, cmp, n2) do { gint64 __n1 = (n1), __n2 = (n2); \
|
|
|
|
if (__n1 cmp __n2) ; else \
|
|
|
|
assert (false); \
|
|
|
|
} while (0)
|
|
|
|
#define g_assert_cmpuint(n1, cmp, n2) do { guint64 __n1 = (n1), __n2 = (n2); \
|
|
|
|
if (__n1 cmp __n2) ; else \
|
|
|
|
assert(false); \
|
|
|
|
} while (0)
|
|
|
|
#define g_assert_cmphex(n1, cmp, n2) do { guint64 __n1 = (n1), __n2 = (n2); \
|
|
|
|
if (__n1 cmp __n2) ; else \
|
|
|
|
assert(false); \
|
|
|
|
} while (0)
|
|
|
|
#define g_assert_cmpfloat(n1,cmp,n2) do { long double __n1 = (n1), __n2 = (n2); \
|
|
|
|
if (__n1 cmp __n2) ; else \
|
|
|
|
assert(false); \
|
|
|
|
} while (0)
|
|
|
|
|
2016-12-18 22:56:58 +00:00
|
|
|
/* typedefs for glib related types that may still be referenced */
|
|
|
|
typedef void* gpointer;
|
|
|
|
typedef const void *gconstpointer;
|
2016-12-19 20:32:06 +00:00
|
|
|
typedef int gint;
|
translate-all: use a binary search tree to track TBs in TBContext
This is a prerequisite for supporting multiple TCG contexts, since
we will have threads generating code in separate regions of
code_gen_buffer.
For this we need a new field (.size) in struct tb_tc to keep
track of the size of the translated code. This field uses a size_t
to avoid adding a hole to the struct, although really an unsigned
int would have been enough.
The comparison function we use is optimized for the common case:
insertions. Profiling shows that upon booting debian-arm, 98%
of comparisons are between existing tb's (i.e. a->size and b->size
are both !0), which happens during insertions (and removals, but
those are rare). The remaining cases are lookups. From reading the glib
sources we see that the first key is always the lookup key. However,
the code does not assume this to always be the case because this
behaviour is not guaranteed in the glib docs. However, we embed
this knowledge in the code as a branch hint for the compiler.
Note that tb_free does not free space in the code_gen_buffer anymore,
since we cannot easily know whether the tb is the last one inserted
in code_gen_buffer. The next patch in this series renames tb_free
to tb_remove to reflect this.
Performance-wise, lookups in tb_find_pc are the same as before:
O(log n). However, insertions are O(log n) instead of O(1), which
results in a small slowdown when booting debian-arm:
Performance counter stats for 'build/arm-softmmu/qemu-system-arm \
-machine type=virt -nographic -smp 1 -m 4096 \
-netdev user,id=unet,hostfwd=tcp::2222-:22 \
-device virtio-net-device,netdev=unet \
-drive file=img/arm/jessie-arm32.qcow2,id=myblock,index=0,if=none \
-device virtio-blk-device,drive=myblock \
-kernel img/arm/aarch32-current-linux-kernel-only.img \
-append console=ttyAMA0 root=/dev/vda1 \
-name arm,debug-threads=on -smp 1' (10 runs):
- Before:
8048.598422 task-clock (msec) # 0.931 CPUs utilized ( +- 0.28% )
16,974 context-switches # 0.002 M/sec ( +- 0.12% )
0 cpu-migrations # 0.000 K/sec
10,125 page-faults # 0.001 M/sec ( +- 1.23% )
35,144,901,879 cycles # 4.367 GHz ( +- 0.14% )
<not supported> stalled-cycles-frontend
<not supported> stalled-cycles-backend
65,758,252,643 instructions # 1.87 insns per cycle ( +- 0.33% )
10,871,298,668 branches # 1350.707 M/sec ( +- 0.41% )
192,322,212 branch-misses # 1.77% of all branches ( +- 0.32% )
8.640869419 seconds time elapsed ( +- 0.57% )
- After:
8146.242027 task-clock (msec) # 0.923 CPUs utilized ( +- 1.23% )
17,016 context-switches # 0.002 M/sec ( +- 0.40% )
0 cpu-migrations # 0.000 K/sec
18,769 page-faults # 0.002 M/sec ( +- 0.45% )
35,660,956,120 cycles # 4.378 GHz ( +- 1.22% )
<not supported> stalled-cycles-frontend
<not supported> stalled-cycles-backend
65,095,366,607 instructions # 1.83 insns per cycle ( +- 1.73% )
10,803,480,261 branches # 1326.192 M/sec ( +- 1.95% )
195,601,289 branch-misses # 1.81% of all branches ( +- 0.39% )
8.828660235 seconds time elapsed ( +- 0.38% )
Backports commit 2ac01d6dafabd4a726254eea98824c798d416ee4 from qemu
2018-03-13 19:34:46 +00:00
|
|
|
typedef signed char gint8;
|
|
|
|
typedef unsigned char guint8;
|
|
|
|
typedef signed short gint16;
|
|
|
|
typedef unsigned short guint16;
|
2016-12-26 12:12:01 +00:00
|
|
|
typedef uint32_t guint32;
|
2017-01-01 17:24:54 +00:00
|
|
|
typedef uint64_t guint64;
|
2016-12-19 20:32:06 +00:00
|
|
|
typedef unsigned int guint;
|
2016-12-18 22:56:58 +00:00
|
|
|
typedef char gchar;
|
2018-02-14 14:08:13 +00:00
|
|
|
typedef unsigned char guchar;
|
2016-12-18 22:56:58 +00:00
|
|
|
typedef int gboolean;
|
2016-12-26 12:12:01 +00:00
|
|
|
typedef unsigned long gulong;
|
2016-12-26 14:36:47 +00:00
|
|
|
typedef unsigned long gsize;
|
qapi: Improve qobject input visitor error reporting
Error messages refer to nodes of the QObject being visited by name.
Trouble is the names are sometimes less than helpful:
* The name of the root QObject is whatever @name argument got passed
to the visitor, except NULL gets mapped to "null". We commonly pass
NULL. Not good.
Avoiding errors "at the root" mitigates. For instance,
visit_start_struct() can only fail when the visited object is not a
dictionary, and we commonly ensure it is beforehand.
* The name of a QDict's member is the member key. Good enough only
when this happens to be unique.
* The name of a QList's member is "null". Not good.
Improve error messages by referring to nodes by path instead, as
follows:
* The path of the root QObject is whatever @name argument got passed
to the visitor, except NULL gets mapped to "<anonymous>".
* The path of a root QDict's member is the member key.
* The path of a root QList's member is "[%u]", where %u is the list
index, starting at zero.
* The path of a non-root QDict's member is the path of the QDict
concatenated with "." and the member key.
* The path of a non-root QList's member is the path of the QList
concatenated with "[%u]", where %u is the list index.
For example, the incorrect QMP command
{ "execute": "blockdev-add", "arguments": { "node-name": "foo", "driver": "raw", "file": {"driver": "file" } } }
now fails with
{"error": {"class": "GenericError", "desc": "Parameter 'file.filename' is missing"}}
instead of
{"error": {"class": "GenericError", "desc": "Parameter 'filename' is missing"}}
and
{ "execute": "input-send-event", "arguments": { "device": "bar", "events": [ [] ] } }
now fails with
{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'events[0]', expected: object"}}
instead of
{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'null', expected: QDict"}}
Aside: calling the thing "parameter" is suboptimal for QMP, because
the root object is "arguments" there.
The qobject output visitor doesn't have this problem because it should
not fail. Same for dealloc and clone visitors.
The string visitors don't have this problem because they visit just
one value, whose name needs to be passed to the visitor as @name. The
string output visitor shouldn't fail anyway.
The options visitor uses QemuOpts names. Their name space is flat, so
the use of QDict member keys as names is fine. NULL names used with
roots and lists could conceivably result in bad error messages. Left
for another day.
Backports commit a9fc37f6bc3f2ab90585cb16493da9f6dcfbfbcf from qemu
2018-03-02 16:37:04 +00:00
|
|
|
typedef signed long gssize;
|
2016-12-18 22:56:58 +00:00
|
|
|
|
translate-all: use a binary search tree to track TBs in TBContext
This is a prerequisite for supporting multiple TCG contexts, since
we will have threads generating code in separate regions of
code_gen_buffer.
For this we need a new field (.size) in struct tb_tc to keep
track of the size of the translated code. This field uses a size_t
to avoid adding a hole to the struct, although really an unsigned
int would have been enough.
The comparison function we use is optimized for the common case:
insertions. Profiling shows that upon booting debian-arm, 98%
of comparisons are between existing tb's (i.e. a->size and b->size
are both !0), which happens during insertions (and removals, but
those are rare). The remaining cases are lookups. From reading the glib
sources we see that the first key is always the lookup key. However,
the code does not assume this to always be the case because this
behaviour is not guaranteed in the glib docs. However, we embed
this knowledge in the code as a branch hint for the compiler.
Note that tb_free does not free space in the code_gen_buffer anymore,
since we cannot easily know whether the tb is the last one inserted
in code_gen_buffer. The next patch in this series renames tb_free
to tb_remove to reflect this.
Performance-wise, lookups in tb_find_pc are the same as before:
O(log n). However, insertions are O(log n) instead of O(1), which
results in a small slowdown when booting debian-arm:
Performance counter stats for 'build/arm-softmmu/qemu-system-arm \
-machine type=virt -nographic -smp 1 -m 4096 \
-netdev user,id=unet,hostfwd=tcp::2222-:22 \
-device virtio-net-device,netdev=unet \
-drive file=img/arm/jessie-arm32.qcow2,id=myblock,index=0,if=none \
-device virtio-blk-device,drive=myblock \
-kernel img/arm/aarch32-current-linux-kernel-only.img \
-append console=ttyAMA0 root=/dev/vda1 \
-name arm,debug-threads=on -smp 1' (10 runs):
- Before:
8048.598422 task-clock (msec) # 0.931 CPUs utilized ( +- 0.28% )
16,974 context-switches # 0.002 M/sec ( +- 0.12% )
0 cpu-migrations # 0.000 K/sec
10,125 page-faults # 0.001 M/sec ( +- 1.23% )
35,144,901,879 cycles # 4.367 GHz ( +- 0.14% )
<not supported> stalled-cycles-frontend
<not supported> stalled-cycles-backend
65,758,252,643 instructions # 1.87 insns per cycle ( +- 0.33% )
10,871,298,668 branches # 1350.707 M/sec ( +- 0.41% )
192,322,212 branch-misses # 1.77% of all branches ( +- 0.32% )
8.640869419 seconds time elapsed ( +- 0.57% )
- After:
8146.242027 task-clock (msec) # 0.923 CPUs utilized ( +- 1.23% )
17,016 context-switches # 0.002 M/sec ( +- 0.40% )
0 cpu-migrations # 0.000 K/sec
18,769 page-faults # 0.002 M/sec ( +- 0.45% )
35,660,956,120 cycles # 4.378 GHz ( +- 1.22% )
<not supported> stalled-cycles-frontend
<not supported> stalled-cycles-backend
65,095,366,607 instructions # 1.83 insns per cycle ( +- 1.73% )
10,803,480,261 branches # 1326.192 M/sec ( +- 1.95% )
195,601,289 branch-misses # 1.81% of all branches ( +- 0.39% )
8.828660235 seconds time elapsed ( +- 0.38% )
Backports commit 2ac01d6dafabd4a726254eea98824c798d416ee4 from qemu
2018-03-13 19:34:46 +00:00
|
|
|
typedef gint (*GCompareFunc)(gconstpointer a, gconstpointer b);
|
|
|
|
typedef gint (*GCompareDataFunc)(gconstpointer a, gconstpointer b,
|
|
|
|
gpointer user_data);
|
|
|
|
typedef gboolean (*GEqualFunc)(gconstpointer a, gconstpointer b);
|
2016-12-25 17:35:42 +00:00
|
|
|
typedef void (*GDestroyNotify)(gpointer data);
|
translate-all: use a binary search tree to track TBs in TBContext
This is a prerequisite for supporting multiple TCG contexts, since
we will have threads generating code in separate regions of
code_gen_buffer.
For this we need a new field (.size) in struct tb_tc to keep
track of the size of the translated code. This field uses a size_t
to avoid adding a hole to the struct, although really an unsigned
int would have been enough.
The comparison function we use is optimized for the common case:
insertions. Profiling shows that upon booting debian-arm, 98%
of comparisons are between existing tb's (i.e. a->size and b->size
are both !0), which happens during insertions (and removals, but
those are rare). The remaining cases are lookups. From reading the glib
sources we see that the first key is always the lookup key. However,
the code does not assume this to always be the case because this
behaviour is not guaranteed in the glib docs. However, we embed
this knowledge in the code as a branch hint for the compiler.
Note that tb_free does not free space in the code_gen_buffer anymore,
since we cannot easily know whether the tb is the last one inserted
in code_gen_buffer. The next patch in this series renames tb_free
to tb_remove to reflect this.
Performance-wise, lookups in tb_find_pc are the same as before:
O(log n). However, insertions are O(log n) instead of O(1), which
results in a small slowdown when booting debian-arm:
Performance counter stats for 'build/arm-softmmu/qemu-system-arm \
-machine type=virt -nographic -smp 1 -m 4096 \
-netdev user,id=unet,hostfwd=tcp::2222-:22 \
-device virtio-net-device,netdev=unet \
-drive file=img/arm/jessie-arm32.qcow2,id=myblock,index=0,if=none \
-device virtio-blk-device,drive=myblock \
-kernel img/arm/aarch32-current-linux-kernel-only.img \
-append console=ttyAMA0 root=/dev/vda1 \
-name arm,debug-threads=on -smp 1' (10 runs):
- Before:
8048.598422 task-clock (msec) # 0.931 CPUs utilized ( +- 0.28% )
16,974 context-switches # 0.002 M/sec ( +- 0.12% )
0 cpu-migrations # 0.000 K/sec
10,125 page-faults # 0.001 M/sec ( +- 1.23% )
35,144,901,879 cycles # 4.367 GHz ( +- 0.14% )
<not supported> stalled-cycles-frontend
<not supported> stalled-cycles-backend
65,758,252,643 instructions # 1.87 insns per cycle ( +- 0.33% )
10,871,298,668 branches # 1350.707 M/sec ( +- 0.41% )
192,322,212 branch-misses # 1.77% of all branches ( +- 0.32% )
8.640869419 seconds time elapsed ( +- 0.57% )
- After:
8146.242027 task-clock (msec) # 0.923 CPUs utilized ( +- 1.23% )
17,016 context-switches # 0.002 M/sec ( +- 0.40% )
0 cpu-migrations # 0.000 K/sec
18,769 page-faults # 0.002 M/sec ( +- 0.45% )
35,660,956,120 cycles # 4.378 GHz ( +- 1.22% )
<not supported> stalled-cycles-frontend
<not supported> stalled-cycles-backend
65,095,366,607 instructions # 1.83 insns per cycle ( +- 1.73% )
10,803,480,261 branches # 1326.192 M/sec ( +- 1.95% )
195,601,289 branch-misses # 1.81% of all branches ( +- 0.39% )
8.828660235 seconds time elapsed ( +- 0.38% )
Backports commit 2ac01d6dafabd4a726254eea98824c798d416ee4 from qemu
2018-03-13 19:34:46 +00:00
|
|
|
typedef void (*GFunc)(gpointer data, gpointer user_data);
|
|
|
|
typedef guint (*GHashFunc)(gconstpointer key);
|
|
|
|
typedef void (*GHFunc)(gpointer key, gpointer value, gpointer user_data);
|
|
|
|
typedef void (*GFreeFunc)(gpointer data);
|
|
|
|
|
|
|
|
/* Tree traverse orders */
|
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
G_IN_ORDER,
|
|
|
|
G_PRE_ORDER,
|
|
|
|
G_POST_ORDER,
|
|
|
|
G_LEVEL_ORDER
|
|
|
|
} GTraverseType;
|
2016-12-18 22:56:58 +00:00
|
|
|
|
2018-03-12 01:48:48 +00:00
|
|
|
guint g_direct_hash(gconstpointer v);
|
|
|
|
gboolean g_direct_equal(gconstpointer v1, gconstpointer v2);
|
|
|
|
|
2016-12-25 17:35:42 +00:00
|
|
|
guint g_str_hash(gconstpointer v);
|
|
|
|
gboolean g_str_equal(gconstpointer v1, gconstpointer v2);
|
2018-03-11 18:29:19 +00:00
|
|
|
gboolean g_str_has_suffix(const gchar *str, const gchar *prefix);
|
|
|
|
gboolean g_str_has_prefix(const gchar *str, const gchar *prefix);
|
2016-12-25 17:35:42 +00:00
|
|
|
|
2018-03-11 18:29:19 +00:00
|
|
|
guint g_int_hash(gconstpointer v);
|
2016-12-25 17:35:42 +00:00
|
|
|
gboolean g_int_equal(gconstpointer v1, gconstpointer v2);
|
2016-12-18 22:56:58 +00:00
|
|
|
|
|
|
|
typedef struct _GList {
|
2016-12-25 17:35:42 +00:00
|
|
|
gpointer data;
|
2016-12-18 22:56:58 +00:00
|
|
|
struct _GList *next;
|
|
|
|
struct _GList *prev;
|
|
|
|
} GList;
|
|
|
|
|
|
|
|
GList *g_list_first(GList *list);
|
2016-12-25 17:35:42 +00:00
|
|
|
void g_list_foreach(GList *list, GFunc func, gpointer user_data);
|
2016-12-18 22:56:58 +00:00
|
|
|
void g_list_free(GList *list);
|
qapi: Fix memleak in string visitors on int lists
Commit 7f8f9ef1 introduced the ability to store a list of
integers as a sorted list of ranges, but when merging ranges,
it leaks one or more ranges. It was also using range_get_last()
incorrectly within range_compare() (a range is a start/end pair,
but range_get_last() is for start/len pairs), and will also
mishandle a range ending in UINT64_MAX (remember, we document
that no range covers 2**64 bytes, but that ranges that end on
UINT64_MAX have end < begin).
The whole merge algorithm was rather complex, and included
unnecessary passes over data within glib functions, and enough
indirection to make it hard to easily plug the data leaks.
Since we are already hard-coding things to a list of ranges,
just rewrite the thing to open-code the traversal and
comparisons, by making the range_compare() helper function give
us an answer that is easier to use, at which point we avoid the
need to pass any callbacks to g_list_*(). Then by reusing
range_extend() instead of duplicating effort with range_merge(),
we cover the corner cases correctly.
Drop the now-unused range_merge() and ranges_can_merge().
Doing this lets test-string-{input,output}-visitor pass under
valgrind without leaks.
Backports commit db486cc334aafd3dbdaf107388e37fc3d6d3e171 from qemu
2018-02-25 05:05:52 +00:00
|
|
|
GList* g_list_insert_before(GList *list, GList *sibling, gpointer data);
|
2016-12-25 17:35:42 +00:00
|
|
|
GList *g_list_insert_sorted(GList *list, gpointer data, GCompareFunc compare);
|
2016-12-18 22:56:58 +00:00
|
|
|
#define g_list_next(list) (list->next)
|
2016-12-25 17:35:42 +00:00
|
|
|
GList *g_list_prepend(GList *list, gpointer data);
|
2016-12-18 22:56:58 +00:00
|
|
|
GList *g_list_remove_link(GList *list, GList *llink);
|
qapi: Fix memleak in string visitors on int lists
Commit 7f8f9ef1 introduced the ability to store a list of
integers as a sorted list of ranges, but when merging ranges,
it leaks one or more ranges. It was also using range_get_last()
incorrectly within range_compare() (a range is a start/end pair,
but range_get_last() is for start/len pairs), and will also
mishandle a range ending in UINT64_MAX (remember, we document
that no range covers 2**64 bytes, but that ranges that end on
UINT64_MAX have end < begin).
The whole merge algorithm was rather complex, and included
unnecessary passes over data within glib functions, and enough
indirection to make it hard to easily plug the data leaks.
Since we are already hard-coding things to a list of ranges,
just rewrite the thing to open-code the traversal and
comparisons, by making the range_compare() helper function give
us an answer that is easier to use, at which point we avoid the
need to pass any callbacks to g_list_*(). Then by reusing
range_extend() instead of duplicating effort with range_merge(),
we cover the corner cases correctly.
Drop the now-unused range_merge() and ranges_can_merge().
Doing this lets test-string-{input,output}-visitor pass under
valgrind without leaks.
Backports commit db486cc334aafd3dbdaf107388e37fc3d6d3e171 from qemu
2018-02-25 05:05:52 +00:00
|
|
|
GList *g_list_delete_link (GList *list, GList *link_);
|
2016-12-19 20:32:06 +00:00
|
|
|
GList *g_list_sort(GList *list, GCompareFunc compare);
|
2016-12-18 22:56:58 +00:00
|
|
|
|
|
|
|
typedef struct _GSList {
|
2016-12-25 17:35:42 +00:00
|
|
|
gpointer data;
|
2016-12-18 22:56:58 +00:00
|
|
|
struct _GSList *next;
|
|
|
|
} GSList;
|
|
|
|
|
2016-12-25 17:35:42 +00:00
|
|
|
GSList *g_slist_append(GSList *list, gpointer data);
|
|
|
|
void g_slist_foreach(GSList *list, GFunc func, gpointer user_data);
|
2016-12-18 22:56:58 +00:00
|
|
|
void g_slist_free(GSList *list);
|
2016-12-25 17:35:42 +00:00
|
|
|
GSList *g_slist_prepend(GSList *list, gpointer data);
|
2016-12-19 20:32:06 +00:00
|
|
|
GSList *g_slist_sort(GSList *list, GCompareFunc compare);
|
2016-12-18 22:56:58 +00:00
|
|
|
|
qapi: Improve qobject input visitor error reporting
Error messages refer to nodes of the QObject being visited by name.
Trouble is the names are sometimes less than helpful:
* The name of the root QObject is whatever @name argument got passed
to the visitor, except NULL gets mapped to "null". We commonly pass
NULL. Not good.
Avoiding errors "at the root" mitigates. For instance,
visit_start_struct() can only fail when the visited object is not a
dictionary, and we commonly ensure it is beforehand.
* The name of a QDict's member is the member key. Good enough only
when this happens to be unique.
* The name of a QList's member is "null". Not good.
Improve error messages by referring to nodes by path instead, as
follows:
* The path of the root QObject is whatever @name argument got passed
to the visitor, except NULL gets mapped to "<anonymous>".
* The path of a root QDict's member is the member key.
* The path of a root QList's member is "[%u]", where %u is the list
index, starting at zero.
* The path of a non-root QDict's member is the path of the QDict
concatenated with "." and the member key.
* The path of a non-root QList's member is the path of the QList
concatenated with "[%u]", where %u is the list index.
For example, the incorrect QMP command
{ "execute": "blockdev-add", "arguments": { "node-name": "foo", "driver": "raw", "file": {"driver": "file" } } }
now fails with
{"error": {"class": "GenericError", "desc": "Parameter 'file.filename' is missing"}}
instead of
{"error": {"class": "GenericError", "desc": "Parameter 'filename' is missing"}}
and
{ "execute": "input-send-event", "arguments": { "device": "bar", "events": [ [] ] } }
now fails with
{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'events[0]', expected: object"}}
instead of
{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'null', expected: QDict"}}
Aside: calling the thing "parameter" is suboptimal for QMP, because
the root object is "arguments" there.
The qobject output visitor doesn't have this problem because it should
not fail. Same for dealloc and clone visitors.
The string visitors don't have this problem because they visit just
one value, whose name needs to be passed to the visitor as @name. The
string output visitor shouldn't fail anyway.
The options visitor uses QemuOpts names. Their name space is flat, so
the use of QDict member keys as names is fine. NULL names used with
roots and lists could conceivably result in bad error messages. Left
for another day.
Backports commit a9fc37f6bc3f2ab90585cb16493da9f6dcfbfbcf from qemu
2018-03-02 16:37:04 +00:00
|
|
|
typedef struct _GString GString;
|
|
|
|
|
|
|
|
struct _GString
|
|
|
|
{
|
|
|
|
gchar *str;
|
|
|
|
gsize len;
|
|
|
|
gsize allocated_len;
|
|
|
|
};
|
|
|
|
|
|
|
|
GString* g_string_new(const gchar *init);
|
|
|
|
GString* g_string_sized_new(gsize dfl_size);
|
|
|
|
gchar* g_string_free(GString *string, gboolean free_segment);
|
|
|
|
GString* g_string_erase(GString *string, gssize pos, gssize len);
|
|
|
|
GString* g_string_append_len(GString *string, const gchar *val, gssize len);
|
|
|
|
GString* g_string_insert_c(GString *string, gssize pos, gchar c);
|
|
|
|
GString* g_string_insert_len(GString *string, gssize pos, const gchar *val, gssize len);
|
|
|
|
GString* g_string_prepend(GString *string, const gchar *val);
|
|
|
|
GString* g_string_prepend_c(GString *string, gchar c);
|
|
|
|
GString* g_string_truncate(GString *string, gsize len);
|
|
|
|
GString* g_string_set_size(GString *string, gsize len);
|
|
|
|
|
2016-12-25 17:35:42 +00:00
|
|
|
typedef guint (*GHashFunc)(gconstpointer key);
|
|
|
|
typedef gboolean (*GEqualFunc)(gconstpointer a, gconstpointer b);
|
|
|
|
typedef void (*GHFunc)(gpointer key, gpointer value, gpointer user_data);
|
|
|
|
typedef gboolean (*GHRFunc)(gpointer key, gpointer value, gpointer user_data);
|
2016-12-18 22:56:58 +00:00
|
|
|
|
|
|
|
typedef struct _GHashTable GHashTable;
|
2018-02-21 18:04:14 +00:00
|
|
|
typedef struct _GHashTableIter GHashTableIter;
|
|
|
|
|
|
|
|
struct _GHashTableIter
|
|
|
|
{
|
|
|
|
/*< private >*/
|
|
|
|
gpointer dummy1;
|
|
|
|
gpointer dummy2;
|
|
|
|
gpointer dummy3;
|
|
|
|
int dummy4;
|
|
|
|
gboolean dummy5;
|
|
|
|
gpointer dummy6;
|
|
|
|
};
|
2016-12-18 22:56:58 +00:00
|
|
|
|
|
|
|
void g_hash_table_destroy(GHashTable *hash_table);
|
2016-12-25 17:35:42 +00:00
|
|
|
gpointer g_hash_table_find(GHashTable *hash_table, GHRFunc predicate, gpointer user_data);
|
|
|
|
void g_hash_table_foreach(GHashTable *hash_table, GHFunc func, gpointer user_data);
|
2016-12-26 12:12:01 +00:00
|
|
|
void g_hash_table_insert(GHashTable *hash_table, gpointer key, gpointer value);
|
2018-03-12 01:48:48 +00:00
|
|
|
void g_hash_table_replace(GHashTable *hash_table, gpointer key, gpointer value);
|
2016-12-25 17:35:42 +00:00
|
|
|
gpointer g_hash_table_lookup(GHashTable *hash_table, gconstpointer key);
|
2016-12-18 22:56:58 +00:00
|
|
|
GHashTable *g_hash_table_new(GHashFunc hash_func, GEqualFunc key_equal_func);
|
2018-03-12 01:48:48 +00:00
|
|
|
GHashTable *g_hash_table_new_full(GHashFunc hash_func, GEqualFunc key_equal_func,
|
2016-12-18 22:56:58 +00:00
|
|
|
GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func);
|
|
|
|
void g_hash_table_remove_all(GHashTable *hash_table);
|
2016-12-25 17:35:42 +00:00
|
|
|
gboolean g_hash_table_remove(GHashTable *hash_table, gconstpointer key);
|
2016-12-18 22:56:58 +00:00
|
|
|
void g_hash_table_unref(GHashTable *hash_table);
|
|
|
|
GHashTable *g_hash_table_ref(GHashTable *hash_table);
|
2016-12-19 20:32:06 +00:00
|
|
|
guint g_hash_table_size(GHashTable *hash_table);
|
2016-12-18 22:56:58 +00:00
|
|
|
|
2018-02-21 18:04:14 +00:00
|
|
|
void g_hash_table_iter_init(GHashTableIter *iter, GHashTable *hash_table);
|
|
|
|
gboolean g_hash_table_iter_next(GHashTableIter *iter, gpointer *key, gpointer *value);
|
|
|
|
GHashTable *g_hash_table_iter_get_hash_table(GHashTableIter *iter);
|
|
|
|
void g_hash_table_iter_remove(GHashTableIter *iter);
|
|
|
|
void g_hash_table_iter_steal(GHashTableIter *iter);
|
|
|
|
|
translate-all: use a binary search tree to track TBs in TBContext
This is a prerequisite for supporting multiple TCG contexts, since
we will have threads generating code in separate regions of
code_gen_buffer.
For this we need a new field (.size) in struct tb_tc to keep
track of the size of the translated code. This field uses a size_t
to avoid adding a hole to the struct, although really an unsigned
int would have been enough.
The comparison function we use is optimized for the common case:
insertions. Profiling shows that upon booting debian-arm, 98%
of comparisons are between existing tb's (i.e. a->size and b->size
are both !0), which happens during insertions (and removals, but
those are rare). The remaining cases are lookups. From reading the glib
sources we see that the first key is always the lookup key. However,
the code does not assume this to always be the case because this
behaviour is not guaranteed in the glib docs. However, we embed
this knowledge in the code as a branch hint for the compiler.
Note that tb_free does not free space in the code_gen_buffer anymore,
since we cannot easily know whether the tb is the last one inserted
in code_gen_buffer. The next patch in this series renames tb_free
to tb_remove to reflect this.
Performance-wise, lookups in tb_find_pc are the same as before:
O(log n). However, insertions are O(log n) instead of O(1), which
results in a small slowdown when booting debian-arm:
Performance counter stats for 'build/arm-softmmu/qemu-system-arm \
-machine type=virt -nographic -smp 1 -m 4096 \
-netdev user,id=unet,hostfwd=tcp::2222-:22 \
-device virtio-net-device,netdev=unet \
-drive file=img/arm/jessie-arm32.qcow2,id=myblock,index=0,if=none \
-device virtio-blk-device,drive=myblock \
-kernel img/arm/aarch32-current-linux-kernel-only.img \
-append console=ttyAMA0 root=/dev/vda1 \
-name arm,debug-threads=on -smp 1' (10 runs):
- Before:
8048.598422 task-clock (msec) # 0.931 CPUs utilized ( +- 0.28% )
16,974 context-switches # 0.002 M/sec ( +- 0.12% )
0 cpu-migrations # 0.000 K/sec
10,125 page-faults # 0.001 M/sec ( +- 1.23% )
35,144,901,879 cycles # 4.367 GHz ( +- 0.14% )
<not supported> stalled-cycles-frontend
<not supported> stalled-cycles-backend
65,758,252,643 instructions # 1.87 insns per cycle ( +- 0.33% )
10,871,298,668 branches # 1350.707 M/sec ( +- 0.41% )
192,322,212 branch-misses # 1.77% of all branches ( +- 0.32% )
8.640869419 seconds time elapsed ( +- 0.57% )
- After:
8146.242027 task-clock (msec) # 0.923 CPUs utilized ( +- 1.23% )
17,016 context-switches # 0.002 M/sec ( +- 0.40% )
0 cpu-migrations # 0.000 K/sec
18,769 page-faults # 0.002 M/sec ( +- 0.45% )
35,660,956,120 cycles # 4.378 GHz ( +- 1.22% )
<not supported> stalled-cycles-frontend
<not supported> stalled-cycles-backend
65,095,366,607 instructions # 1.83 insns per cycle ( +- 1.73% )
10,803,480,261 branches # 1326.192 M/sec ( +- 1.95% )
195,601,289 branch-misses # 1.81% of all branches ( +- 0.39% )
8.828660235 seconds time elapsed ( +- 0.38% )
Backports commit 2ac01d6dafabd4a726254eea98824c798d416ee4 from qemu
2018-03-13 19:34:46 +00:00
|
|
|
/* Tree code */
|
|
|
|
typedef struct _GTree GTree;
|
|
|
|
|
|
|
|
typedef gboolean (*GTraverseFunc) (gpointer key,
|
|
|
|
gpointer value,
|
|
|
|
gpointer data);
|
|
|
|
|
|
|
|
GTree *g_tree_new(GCompareFunc key_compare_func);
|
|
|
|
GTree *g_tree_new_with_data(GCompareDataFunc key_compare_func,
|
|
|
|
gpointer key_compare_data);
|
|
|
|
GTree *g_tree_new_full(GCompareDataFunc key_compare_func,
|
|
|
|
gpointer key_compare_data,
|
|
|
|
GDestroyNotify key_destroy_func,
|
|
|
|
GDestroyNotify value_destroy_func);
|
|
|
|
GTree *g_tree_ref(GTree *tree);
|
|
|
|
void g_tree_unref(GTree *tree);
|
|
|
|
void g_tree_destroy(GTree *tree);
|
|
|
|
void g_tree_insert(GTree *tree, gpointer key, gpointer value);
|
|
|
|
void g_tree_replace(GTree *tree, gpointer key, gpointer value);
|
|
|
|
gboolean g_tree_remove(GTree *tree, gconstpointer key);
|
|
|
|
gboolean g_tree_steal(GTree *tree, gconstpointer key);
|
|
|
|
gpointer g_tree_lookup(GTree *tree, gconstpointer key);
|
|
|
|
gboolean g_tree_lookup_extended(GTree *tree, gconstpointer lookup_key,
|
|
|
|
gpointer *orig_key, gpointer *value);
|
|
|
|
void g_tree_foreach(GTree *tree, GTraverseFunc func, gpointer user_data);
|
|
|
|
gpointer g_tree_search(GTree *tree, GCompareFunc search_func, gconstpointer user_data);
|
|
|
|
gint g_tree_height(GTree *tree);
|
|
|
|
gint g_tree_nnodes(GTree *tree);
|
|
|
|
void g_tree_traverse(GTree *tree, GTraverseFunc traverse_func, GTraverseType traverse_type, gpointer user_data);
|
|
|
|
|
2016-12-18 22:56:58 +00:00
|
|
|
/* replacement for g_malloc dependency */
|
2016-12-25 17:35:42 +00:00
|
|
|
void g_free(gpointer ptr);
|
|
|
|
gpointer g_malloc(size_t size);
|
|
|
|
gpointer g_malloc0(size_t size);
|
|
|
|
gpointer g_try_malloc0(size_t size);
|
|
|
|
gpointer g_realloc(gpointer ptr, size_t size);
|
2016-12-18 22:56:58 +00:00
|
|
|
char *g_strdup(const char *str);
|
|
|
|
char *g_strdup_printf(const char *format, ...);
|
|
|
|
char *g_strdup_vprintf(const char *format, va_list ap);
|
|
|
|
char *g_strndup(const char *str, size_t n);
|
|
|
|
void g_strfreev(char **v);
|
2016-12-25 17:35:42 +00:00
|
|
|
gpointer g_memdup(gconstpointer mem, size_t byte_size);
|
|
|
|
gpointer g_new_(size_t sz, size_t n_structs);
|
|
|
|
gpointer g_new0_(size_t sz, size_t n_structs);
|
|
|
|
gpointer g_renew_(size_t sz, gpointer mem, size_t n_structs);
|
2016-12-26 14:36:47 +00:00
|
|
|
gchar* g_strconcat (const gchar *string1, ...);
|
|
|
|
gchar** g_strsplit (const gchar *string,
|
|
|
|
const gchar *delimiter,
|
|
|
|
gint max_tokens);
|
2016-12-18 22:56:58 +00:00
|
|
|
|
2018-02-14 14:08:13 +00:00
|
|
|
/* replacement for base64 dependency */
|
|
|
|
gsize g_base64_encode_close(gboolean break_lines, gchar *out,
|
|
|
|
gint *state, gint *save);
|
|
|
|
gchar *g_base64_encode(const guchar *data, gsize len);
|
|
|
|
guchar *g_base64_decode(const gchar *text, gsize *out_len);
|
|
|
|
guchar *g_base64_decode_inplace(gchar *text, gsize *out_len);
|
2016-12-18 22:56:58 +00:00
|
|
|
|
|
|
|
#define g_new(struct_type, n_structs) ((struct_type*)g_new_(sizeof(struct_type), n_structs))
|
|
|
|
#define g_new0(struct_type, n_structs) ((struct_type*)g_new0_(sizeof(struct_type), n_structs))
|
|
|
|
#define g_renew(struct_type, mem, n_structs) ((struct_type*)g_renew_(sizeof(struct_type), mem, n_structs))
|
|
|
|
|
|
|
|
#endif
|