summaryrefslogtreecommitdiff
path: root/util
diff options
context:
space:
mode:
authorYonghee Han <onstudy@samsung.com>2016-07-27 16:39:12 +0900
committerYonghee Han <onstudy@samsung.com>2016-07-27 16:47:03 +0900
commita3b133b0ea0696e42fd876b9a803e28bc6ef5299 (patch)
tree68d7537fb9ede28b2e4d2b9f44eb70988279b8ba /util
parent0d6a2f7e595218b5632ba7005128470e65138951 (diff)
downloadqemu-a3b133b0ea0696e42fd876b9a803e28bc6ef5299.tar.gz
qemu-a3b133b0ea0696e42fd876b9a803e28bc6ef5299.tar.bz2
qemu-a3b133b0ea0696e42fd876b9a803e28bc6ef5299.zip
Imported Upstream version 2.3.1upstream/2.3.1
Change-Id: I2161522ea1d7ff10cd1d697609d473243c05e1df
Diffstat (limited to 'util')
-rw-r--r--util/Makefile.objs1
-rw-r--r--util/aes.c2
-rw-r--r--util/cutils.c19
-rw-r--r--util/envlist.c32
-rw-r--r--util/error.c14
-rw-r--r--util/hbitmap.c4
-rw-r--r--util/iov.c4
-rw-r--r--util/oslib-posix.c4
-rw-r--r--util/qemu-config.c99
-rw-r--r--util/qemu-option.c118
-rw-r--r--util/qemu-sockets.c68
-rw-r--r--util/qemu-thread-posix.c45
-rw-r--r--util/qemu-thread-win32.c48
-rw-r--r--util/rcu.c328
-rw-r--r--util/uri.c179
15 files changed, 714 insertions, 251 deletions
diff --git a/util/Makefile.objs b/util/Makefile.objs
index 93007e2f5..ceaba3093 100644
--- a/util/Makefile.objs
+++ b/util/Makefile.objs
@@ -17,3 +17,4 @@ util-obj-y += throttle.o
util-obj-y += getauxval.o
util-obj-y += readline.o
util-obj-y += rfifolock.o
+util-obj-y += rcu.o
diff --git a/util/aes.c b/util/aes.c
index 6058f1950..3d7c4be9b 100644
--- a/util/aes.c
+++ b/util/aes.c
@@ -1161,7 +1161,7 @@ int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
rk += 8;
}
}
- return 0;
+ abort();
}
/**
diff --git a/util/cutils.c b/util/cutils.c
index dbe7412bd..144b25c05 100644
--- a/util/cutils.c
+++ b/util/cutils.c
@@ -483,6 +483,20 @@ int64_t pow2floor(int64_t value)
return value;
}
+/* round up to the nearest power of 2 (0 if overflow) */
+uint64_t pow2ceil(uint64_t value)
+{
+ uint8_t nlz = clz64(value);
+
+ if (is_power_of_2(value)) {
+ return value;
+ }
+ if (!nlz) {
+ return 0;
+ }
+ return 1ULL << (64 - nlz);
+}
+
/*
* Implementation of ULEB128 (http://en.wikipedia.org/wiki/LEB128)
* Input is limited to 14-bit numbers
@@ -523,16 +537,17 @@ int parse_debug_env(const char *name, int max, int initial)
{
char *debug_env = getenv(name);
char *inv = NULL;
- int debug;
+ long debug;
if (!debug_env) {
return initial;
}
+ errno = 0;
debug = strtol(debug_env, &inv, 10);
if (inv == debug_env) {
return initial;
}
- if (debug < 0 || debug > max) {
+ if (debug < 0 || debug > max || errno != 0) {
fprintf(stderr, "warning: %s not in [0, %d]", name, max);
return initial;
}
diff --git a/util/envlist.c b/util/envlist.c
index ebc06cf0f..099a544a4 100644
--- a/util/envlist.c
+++ b/util/envlist.c
@@ -94,30 +94,30 @@ envlist_parse(envlist_t *envlist, const char *env,
{
char *tmpenv, *envvar;
char *envsave = NULL;
-
- assert(callback != NULL);
+ int ret = 0;
+ assert(callback != NULL);
if ((envlist == NULL) || (env == NULL))
return (EINVAL);
- /*
- * We need to make temporary copy of the env string
- * as strtok_r(3) modifies it while it tokenizes.
- */
if ((tmpenv = strdup(env)) == NULL)
return (errno);
-
- envvar = strtok_r(tmpenv, ",", &envsave);
- while (envvar != NULL) {
- if ((*callback)(envlist, envvar) != 0) {
- free(tmpenv);
- return (errno);
+ envsave = tmpenv;
+
+ do {
+ envvar = strchr(tmpenv, ',');
+ if (envvar != NULL) {
+ *envvar = '\0';
+ }
+ if ((*callback)(envlist, tmpenv) != 0) {
+ ret = errno;
+ break;
}
- envvar = strtok_r(NULL, ",", &envsave);
- }
+ tmpenv = envvar + 1;
+ } while (envvar != NULL);
- free(tmpenv);
- return (0);
+ free(envsave);
+ return ret;
}
/*
diff --git a/util/error.c b/util/error.c
index 2ace0d8dd..14f435187 100644
--- a/util/error.c
+++ b/util/error.c
@@ -41,7 +41,7 @@ void error_set(Error **errp, ErrorClass err_class, const char *fmt, ...)
err->err_class = err_class;
if (errp == &error_abort) {
- error_report("%s", error_get_pretty(err));
+ error_report_err(err);
abort();
}
@@ -77,7 +77,7 @@ void error_set_errno(Error **errp, int os_errno, ErrorClass err_class,
err->err_class = err_class;
if (errp == &error_abort) {
- error_report("%s", error_get_pretty(err));
+ error_report_err(err);
abort();
}
@@ -122,7 +122,7 @@ void error_set_win32(Error **errp, int win32_err, ErrorClass err_class,
err->err_class = err_class;
if (errp == &error_abort) {
- error_report("%s", error_get_pretty(err));
+ error_report_err(err);
abort();
}
@@ -152,6 +152,12 @@ const char *error_get_pretty(Error *err)
return err->msg;
}
+void error_report_err(Error *err)
+{
+ error_report("%s", error_get_pretty(err));
+ error_free(err);
+}
+
void error_free(Error *err)
{
if (err) {
@@ -163,7 +169,7 @@ void error_free(Error *err)
void error_propagate(Error **dst_errp, Error *local_err)
{
if (local_err && dst_errp == &error_abort) {
- error_report("%s", error_get_pretty(local_err));
+ error_report_err(local_err);
abort();
} else if (dst_errp && !*dst_errp) {
*dst_errp = local_err;
diff --git a/util/hbitmap.c b/util/hbitmap.c
index b3060e697..ab139717f 100644
--- a/util/hbitmap.c
+++ b/util/hbitmap.c
@@ -373,7 +373,7 @@ void hbitmap_free(HBitmap *hb)
HBitmap *hbitmap_alloc(uint64_t size, int granularity)
{
- HBitmap *hb = g_malloc0(sizeof (struct HBitmap));
+ HBitmap *hb = g_new0(struct HBitmap, 1);
unsigned i;
assert(granularity >= 0 && granularity < 64);
@@ -384,7 +384,7 @@ HBitmap *hbitmap_alloc(uint64_t size, int granularity)
hb->granularity = granularity;
for (i = HBITMAP_LEVELS; i-- > 0; ) {
size = MAX((size + BITS_PER_LONG - 1) >> BITS_PER_LEVEL, 1);
- hb->levels[i] = g_malloc0(size * sizeof(unsigned long));
+ hb->levels[i] = g_new0(unsigned long, size);
}
/* We necessarily have free bits in level 0 due to the definition
diff --git a/util/iov.c b/util/iov.c
index 24566c878..2fb18e665 100644
--- a/util/iov.c
+++ b/util/iov.c
@@ -253,7 +253,7 @@ unsigned iov_copy(struct iovec *dst_iov, unsigned int dst_iov_cnt,
void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint)
{
- qiov->iov = g_malloc(alloc_hint * sizeof(struct iovec));
+ qiov->iov = g_new(struct iovec, alloc_hint);
qiov->niov = 0;
qiov->nalloc = alloc_hint;
qiov->size = 0;
@@ -277,7 +277,7 @@ void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len)
if (qiov->niov == qiov->nalloc) {
qiov->nalloc = 2 * qiov->nalloc + 1;
- qiov->iov = g_realloc(qiov->iov, qiov->nalloc * sizeof(struct iovec));
+ qiov->iov = g_renew(struct iovec, qiov->iov, qiov->nalloc);
}
qiov->iov[qiov->niov].iov_base = base;
qiov->iov[qiov->niov].iov_len = len;
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
index 16fcec2f3..37ffd9624 100644
--- a/util/oslib-posix.c
+++ b/util/oslib-posix.c
@@ -399,10 +399,10 @@ void os_mem_prealloc(int fd, char *area, size_t memory)
} else {
int i;
size_t hpagesize = fd_getpagesize(fd);
+ size_t numpages = DIV_ROUND_UP(memory, hpagesize);
/* MAP_POPULATE silently ignores failures */
- memory = (memory + hpagesize - 1) & -hpagesize;
- for (i = 0; i < (memory / hpagesize); i++) {
+ for (i = 0; i < numpages; i++) {
memset(area + (hpagesize * i), 0, 1);
}
diff --git a/util/qemu-config.c b/util/qemu-config.c
index ba375c014..2d32ce7e9 100644
--- a/util/qemu-config.c
+++ b/util/qemu-config.c
@@ -6,6 +6,7 @@
#include "hw/qdev.h"
#include "qapi/error.h"
#include "qmp-commands.h"
+#include "hw/i386/pc.h"
static QemuOptsList *vm_config_groups[32];
static QemuOptsList *drive_config_groups[4];
@@ -32,8 +33,7 @@ QemuOptsList *qemu_find_opts(const char *group)
ret = find_list(vm_config_groups, group, &local_err);
if (local_err) {
- error_report("%s", error_get_pretty(local_err));
- error_free(local_err);
+ error_report_err(local_err);
}
return ret;
@@ -149,6 +149,84 @@ static CommandLineParameterInfoList *get_drive_infolist(void)
return head;
}
+/* restore machine options that are now machine's properties */
+static QemuOptsList machine_opts = {
+ .merge_lists = true,
+ .head = QTAILQ_HEAD_INITIALIZER(machine_opts.head),
+ .desc = {
+ {
+ .name = "type",
+ .type = QEMU_OPT_STRING,
+ .help = "emulated machine"
+ },{
+ .name = "accel",
+ .type = QEMU_OPT_STRING,
+ .help = "accelerator list",
+ },{
+ .name = "kernel_irqchip",
+ .type = QEMU_OPT_BOOL,
+ .help = "use KVM in-kernel irqchip",
+ },{
+ .name = "kvm_shadow_mem",
+ .type = QEMU_OPT_SIZE,
+ .help = "KVM shadow MMU size",
+ },{
+ .name = "kernel",
+ .type = QEMU_OPT_STRING,
+ .help = "Linux kernel image file",
+ },{
+ .name = "initrd",
+ .type = QEMU_OPT_STRING,
+ .help = "Linux initial ramdisk file",
+ },{
+ .name = "append",
+ .type = QEMU_OPT_STRING,
+ .help = "Linux kernel command line",
+ },{
+ .name = "dtb",
+ .type = QEMU_OPT_STRING,
+ .help = "Linux kernel device tree file",
+ },{
+ .name = "dumpdtb",
+ .type = QEMU_OPT_STRING,
+ .help = "Dump current dtb to a file and quit",
+ },{
+ .name = "phandle_start",
+ .type = QEMU_OPT_NUMBER,
+ .help = "The first phandle ID we may generate dynamically",
+ },{
+ .name = "dt_compatible",
+ .type = QEMU_OPT_STRING,
+ .help = "Overrides the \"compatible\" property of the dt root node",
+ },{
+ .name = "dump-guest-core",
+ .type = QEMU_OPT_BOOL,
+ .help = "Include guest memory in a core dump",
+ },{
+ .name = "mem-merge",
+ .type = QEMU_OPT_BOOL,
+ .help = "enable/disable memory merge support",
+ },{
+ .name = "usb",
+ .type = QEMU_OPT_BOOL,
+ .help = "Set on/off to enable/disable usb",
+ },{
+ .name = "firmware",
+ .type = QEMU_OPT_STRING,
+ .help = "firmware image",
+ },{
+ .name = "iommu",
+ .type = QEMU_OPT_BOOL,
+ .help = "Set on/off to enable/disable Intel IOMMU (VT-d)",
+ },{
+ .name = "suppress-vmdesc",
+ .type = QEMU_OPT_BOOL,
+ .help = "Set on to disable self-describing migration",
+ },
+ { /* End of list */ }
+ }
+};
+
CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option,
const char *option,
Error **errp)
@@ -163,6 +241,8 @@ CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option,
info->option = g_strdup(vm_config_groups[i]->name);
if (!strcmp("drive", vm_config_groups[i]->name)) {
info->parameters = get_drive_infolist();
+ } else if (!strcmp("machine", vm_config_groups[i]->name)) {
+ info->parameters = query_option_descs(machine_opts.desc);
} else {
info->parameters =
query_option_descs(vm_config_groups[i]->desc);
@@ -220,6 +300,7 @@ void qemu_add_opts(QemuOptsList *list)
int qemu_set_option(const char *str)
{
+ Error *local_err = NULL;
char group[64], id[64], arg[64];
QemuOptsList *list;
QemuOpts *opts;
@@ -243,7 +324,9 @@ int qemu_set_option(const char *str)
return -1;
}
- if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
+ qemu_opt_set(opts, arg, str + offset + 1, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
return -1;
}
return 0;
@@ -314,8 +397,7 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
/* group with id */
list = find_list(lists, group, &local_err);
if (local_err) {
- error_report("%s", error_get_pretty(local_err));
- error_free(local_err);
+ error_report_err(local_err);
goto out;
}
opts = qemu_opts_create(list, id, 1, NULL);
@@ -325,8 +407,7 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
/* group without id */
list = find_list(lists, group, &local_err);
if (local_err) {
- error_report("%s", error_get_pretty(local_err));
- error_free(local_err);
+ error_report_err(local_err);
goto out;
}
opts = qemu_opts_create(list, NULL, 0, &error_abort);
@@ -338,7 +419,9 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
error_report("no group defined");
goto out;
}
- if (qemu_opt_set(opts, arg, value) != 0) {
+ qemu_opt_set(opts, arg, value, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
goto out;
}
continue;
diff --git a/util/qemu-option.c b/util/qemu-option.c
index 5d106959c..fda4e5fcb 100644
--- a/util/qemu-option.c
+++ b/util/qemu-option.c
@@ -213,7 +213,7 @@ void parse_option_size(const char *name, const char *value,
bool has_help_option(const char *param)
{
size_t buflen = strlen(param) + 1;
- char *buf = g_malloc0(buflen);
+ char *buf = g_malloc(buflen);
const char *p = param;
bool result = false;
@@ -230,14 +230,14 @@ bool has_help_option(const char *param)
}
out:
- free(buf);
+ g_free(buf);
return result;
}
bool is_valid_option_list(const char *param)
{
size_t buflen = strlen(param) + 1;
- char *buf = g_malloc0(buflen);
+ char *buf = g_malloc(buflen);
const char *p = param;
bool result = true;
@@ -255,7 +255,7 @@ bool is_valid_option_list(const char *param)
}
out:
- free(buf);
+ g_free(buf);
return result;
}
@@ -548,27 +548,14 @@ static void opt_set(QemuOpts *opts, const char *name, const char *value,
}
}
-int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
-{
- Error *local_err = NULL;
-
- opt_set(opts, name, value, false, &local_err);
- if (local_err) {
- qerror_report_err(local_err);
- error_free(local_err);
- return -1;
- }
-
- return 0;
-}
-
-void qemu_opt_set_err(QemuOpts *opts, const char *name, const char *value,
- Error **errp)
+void qemu_opt_set(QemuOpts *opts, const char *name, const char *value,
+ Error **errp)
{
opt_set(opts, name, value, false, errp);
}
-int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val)
+void qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val,
+ Error **errp)
{
QemuOpt *opt;
const QemuOptDesc *desc = opts->list->desc;
@@ -576,9 +563,9 @@ int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val)
opt = g_malloc0(sizeof(*opt));
opt->desc = find_desc_by_name(desc, name);
if (!opt->desc && !opts_accepts_any(opts)) {
- qerror_report(QERR_INVALID_PARAMETER, name);
+ error_set(errp, QERR_INVALID_PARAMETER, name);
g_free(opt);
- return -1;
+ return;
}
opt->name = g_strdup(name);
@@ -586,11 +573,10 @@ int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val)
opt->value.boolean = !!val;
opt->str = g_strdup(val ? "on" : "off");
QTAILQ_INSERT_TAIL(&opts->head, opt, next);
-
- return 0;
}
-int qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val)
+void qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val,
+ Error **errp)
{
QemuOpt *opt;
const QemuOptDesc *desc = opts->list->desc;
@@ -598,9 +584,9 @@ int qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val)
opt = g_malloc0(sizeof(*opt));
opt->desc = find_desc_by_name(desc, name);
if (!opt->desc && !opts_accepts_any(opts)) {
- qerror_report(QERR_INVALID_PARAMETER, name);
+ error_set(errp, QERR_INVALID_PARAMETER, name);
g_free(opt);
- return -1;
+ return;
}
opt->name = g_strdup(name);
@@ -608,8 +594,6 @@ int qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val)
opt->value.uint = val;
opt->str = g_strdup_printf("%" PRId64, val);
QTAILQ_INSERT_TAIL(&opts->head, opt, next);
-
- return 0;
}
int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque,
@@ -692,19 +676,18 @@ void qemu_opts_loc_restore(QemuOpts *opts)
loc_restore(&opts->loc);
}
-int qemu_opts_set(QemuOptsList *list, const char *id,
- const char *name, const char *value)
+void qemu_opts_set(QemuOptsList *list, const char *id,
+ const char *name, const char *value, Error **errp)
{
QemuOpts *opts;
Error *local_err = NULL;
opts = qemu_opts_create(list, id, 1, &local_err);
if (local_err) {
- qerror_report_err(local_err);
- error_free(local_err);
- return -1;
+ error_propagate(errp, local_err);
+ return;
}
- return qemu_opt_set(opts, name, value);
+ qemu_opt_set(opts, name, value, errp);
}
const char *qemu_opts_id(QemuOpts *opts)
@@ -737,14 +720,14 @@ void qemu_opts_del(QemuOpts *opts)
g_free(opts);
}
-void qemu_opts_print(QemuOpts *opts)
+void qemu_opts_print(QemuOpts *opts, const char *sep)
{
QemuOpt *opt;
QemuOptDesc *desc = opts->list->desc;
if (desc[0].name == NULL) {
QTAILQ_FOREACH(opt, &opts->head, next) {
- printf("%s=\"%s\" ", opt->name, opt->str);
+ printf("%s%s=\"%s\"", sep, opt->name, opt->str);
}
return;
}
@@ -757,18 +740,18 @@ void qemu_opts_print(QemuOpts *opts)
continue;
}
if (desc->type == QEMU_OPT_STRING) {
- printf("%s='%s' ", desc->name, value);
+ printf("%s%s='%s'", sep, desc->name, value);
} else if ((desc->type == QEMU_OPT_SIZE ||
desc->type == QEMU_OPT_NUMBER) && opt) {
- printf("%s=%" PRId64 " ", desc->name, opt->value.uint);
+ printf("%s%s=%" PRId64, sep, desc->name, opt->value.uint);
} else {
- printf("%s=%s ", desc->name, value);
+ printf("%s%s=%s", sep, desc->name, value);
}
}
}
-static int opts_do_parse(QemuOpts *opts, const char *params,
- const char *firstname, bool prepend)
+static void opts_do_parse(QemuOpts *opts, const char *params,
+ const char *firstname, bool prepend, Error **errp)
{
char option[128], value[1024];
const char *p,*pe,*pc;
@@ -806,25 +789,30 @@ static int opts_do_parse(QemuOpts *opts, const char *params,
/* store and parse */
opt_set(opts, option, value, prepend, &local_err);
if (local_err) {
- qerror_report_err(local_err);
- error_free(local_err);
- return -1;
+ error_propagate(errp, local_err);
+ return;
}
}
if (*p != ',') {
break;
}
}
- return 0;
}
-int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname)
+/**
+ * Store options parsed from @params into @opts.
+ * If @firstname is non-null, the first key=value in @params may omit
+ * key=, and is treated as if key was @firstname.
+ * On error, store an error object through @errp if non-null.
+ */
+void qemu_opts_do_parse(QemuOpts *opts, const char *params,
+ const char *firstname, Error **errp)
{
- return opts_do_parse(opts, params, firstname, false);
+ opts_do_parse(opts, params, firstname, false, errp);
}
static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
- int permit_abbrev, bool defaults)
+ int permit_abbrev, bool defaults, Error **errp)
{
const char *firstname;
char value[1024], *id = NULL;
@@ -853,14 +841,13 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
assert(!defaults || list->merge_lists);
opts = qemu_opts_create(list, id, !defaults, &local_err);
if (opts == NULL) {
- if (local_err) {
- qerror_report_err(local_err);
- error_free(local_err);
- }
+ error_propagate(errp, local_err);
return NULL;
}
- if (opts_do_parse(opts, params, firstname, defaults) != 0) {
+ opts_do_parse(opts, params, firstname, defaults, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
qemu_opts_del(opts);
return NULL;
}
@@ -868,10 +855,25 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
return opts;
}
+/**
+ * Create a QemuOpts in @list and with options parsed from @params.
+ * If @permit_abbrev, the first key=value in @params may omit key=,
+ * and is treated as if key was @list->implied_opt_name.
+ * Report errors with qerror_report_err().
+ * Return the new QemuOpts on success, null pointer on error.
+ */
QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
int permit_abbrev)
{
- return opts_parse(list, params, permit_abbrev, false);
+ Error *err = NULL;
+ QemuOpts *opts;
+
+ opts = opts_parse(list, params, permit_abbrev, false, &err);
+ if (!opts) {
+ qerror_report_err(err);
+ error_free(err);
+ }
+ return opts;
}
void qemu_opts_set_defaults(QemuOptsList *list, const char *params,
@@ -879,7 +881,7 @@ void qemu_opts_set_defaults(QemuOptsList *list, const char *params,
{
QemuOpts *opts;
- opts = opts_parse(list, params, permit_abbrev, true);
+ opts = opts_parse(list, params, permit_abbrev, true, NULL);
assert(opts);
}
@@ -924,7 +926,7 @@ static void qemu_opts_from_qdict_1(const char *key, QObject *obj, void *opaque)
return;
}
- qemu_opt_set_err(state->opts, key, value, state->errp);
+ qemu_opt_set(state->opts, key, value, state->errp);
}
/*
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index a76bb3c91..87c9bc6c6 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -199,11 +199,13 @@ listen:
freeaddrinfo(res);
return -1;
}
- snprintf(uport, sizeof(uport), "%d", inet_getport(e) - port_offset);
- qemu_opt_set(opts, "host", uaddr);
- qemu_opt_set(opts, "port", uport);
- qemu_opt_set(opts, "ipv6", (e->ai_family == PF_INET6) ? "on" : "off");
- qemu_opt_set(opts, "ipv4", (e->ai_family != PF_INET6) ? "on" : "off");
+ qemu_opt_set(opts, "host", uaddr, &error_abort);
+ qemu_opt_set_number(opts, "port", inet_getport(e) - port_offset,
+ &error_abort);
+ qemu_opt_set_bool(opts, "ipv6", e->ai_family == PF_INET6,
+ &error_abort);
+ qemu_opt_set_bool(opts, "ipv4", e->ai_family != PF_INET6,
+ &error_abort);
freeaddrinfo(res);
return slisten;
}
@@ -512,7 +514,7 @@ InetSocketAddress *inet_parse(const char *str, Error **errp)
{
InetSocketAddress *addr;
const char *optstr, *h;
- char host[64];
+ char host[65];
char port[33];
int to;
int pos;
@@ -580,16 +582,14 @@ static void inet_addr_to_opts(QemuOpts *opts, const InetSocketAddress *addr)
bool ipv6 = addr->ipv6 || !addr->has_ipv6;
if (!ipv4 || !ipv6) {
- qemu_opt_set_bool(opts, "ipv4", ipv4);
- qemu_opt_set_bool(opts, "ipv6", ipv6);
+ qemu_opt_set_bool(opts, "ipv4", ipv4, &error_abort);
+ qemu_opt_set_bool(opts, "ipv6", ipv6, &error_abort);
}
if (addr->has_to) {
- char to[20];
- snprintf(to, sizeof(to), "%d", addr->to);
- qemu_opt_set(opts, "to", to);
+ qemu_opt_set_number(opts, "to", addr->to, &error_abort);
}
- qemu_opt_set(opts, "host", addr->host);
- qemu_opt_set(opts, "port", addr->port);
+ qemu_opt_set(opts, "host", addr->host, &error_abort);
+ qemu_opt_set(opts, "port", addr->port, &error_abort);
}
int inet_listen(const char *str, char *ostr, int olen,
@@ -694,7 +694,7 @@ int unix_listen_opts(QemuOpts *opts, Error **errp)
sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
- error_setg_errno(errp, errno, "Failed to create socket");
+ error_setg_errno(errp, errno, "Failed to create Unix socket");
return -1;
}
@@ -703,9 +703,15 @@ int unix_listen_opts(QemuOpts *opts, Error **errp)
if (path && strlen(path)) {
snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
} else {
- char *tmpdir = getenv("TMPDIR");
- snprintf(un.sun_path, sizeof(un.sun_path), "%s/qemu-socket-XXXXXX",
- tmpdir ? tmpdir : "/tmp");
+ const char *tmpdir = getenv("TMPDIR");
+ tmpdir = tmpdir ? tmpdir : "/tmp";
+ if (snprintf(un.sun_path, sizeof(un.sun_path), "%s/qemu-socket-XXXXXX",
+ tmpdir) >= sizeof(un.sun_path)) {
+ error_setg_errno(errp, errno,
+ "TMPDIR environment variable (%s) too large", tmpdir);
+ goto err;
+ }
+
/*
* This dummy fd usage silences the mktemp() unsecure warning.
* Using mkstemp() doesn't make things more secure here
@@ -713,13 +719,19 @@ int unix_listen_opts(QemuOpts *opts, Error **errp)
* to unlink first and thus re-open the race window. The
* worst case possible is bind() failing, i.e. a DoS attack.
*/
- fd = mkstemp(un.sun_path); close(fd);
- qemu_opt_set(opts, "path", un.sun_path);
+ fd = mkstemp(un.sun_path);
+ if (fd < 0) {
+ error_setg_errno(errp, errno,
+ "Failed to make a temporary socket name in %s", tmpdir);
+ goto err;
+ }
+ close(fd);
+ qemu_opt_set(opts, "path", un.sun_path, &error_abort);
}
unlink(un.sun_path);
if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
- error_setg_errno(errp, errno, "Failed to bind socket");
+ error_setg_errno(errp, errno, "Failed to bind socket to %s", un.sun_path);
goto err;
}
if (listen(sock, 1) < 0) {
@@ -826,11 +838,11 @@ int unix_listen(const char *str, char *ostr, int olen, Error **errp)
if (len) {
path = g_malloc(len+1);
snprintf(path, len+1, "%.*s", len, str);
- qemu_opt_set(opts, "path", path);
+ qemu_opt_set(opts, "path", path, &error_abort);
g_free(path);
}
} else {
- qemu_opt_set(opts, "path", str);
+ qemu_opt_set(opts, "path", str, &error_abort);
}
sock = unix_listen_opts(opts, errp);
@@ -847,7 +859,7 @@ int unix_connect(const char *path, Error **errp)
int sock;
opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
- qemu_opt_set(opts, "path", path);
+ qemu_opt_set(opts, "path", path, &error_abort);
sock = unix_connect_opts(opts, errp, NULL, NULL);
qemu_opts_del(opts);
return sock;
@@ -864,7 +876,7 @@ int unix_nonblocking_connect(const char *path,
g_assert(callback != NULL);
opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
- qemu_opt_set(opts, "path", path);
+ qemu_opt_set(opts, "path", path, &error_abort);
sock = unix_connect_opts(opts, errp, callback, opaque);
qemu_opts_del(opts);
return sock;
@@ -921,7 +933,7 @@ int socket_connect(SocketAddress *addr, Error **errp,
break;
case SOCKET_ADDRESS_KIND_UNIX:
- qemu_opt_set(opts, "path", addr->q_unix->path);
+ qemu_opt_set(opts, "path", addr->q_unix->path, &error_abort);
fd = unix_connect_opts(opts, errp, callback, opaque);
break;
@@ -953,7 +965,7 @@ int socket_listen(SocketAddress *addr, Error **errp)
break;
case SOCKET_ADDRESS_KIND_UNIX:
- qemu_opt_set(opts, "path", addr->q_unix->path);
+ qemu_opt_set(opts, "path", addr->q_unix->path, &error_abort);
fd = unix_listen_opts(opts, errp);
break;
@@ -978,8 +990,8 @@ int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp)
case SOCKET_ADDRESS_KIND_INET:
inet_addr_to_opts(opts, remote->inet);
if (local) {
- qemu_opt_set(opts, "localaddr", local->inet->host);
- qemu_opt_set(opts, "localport", local->inet->port);
+ qemu_opt_set(opts, "localaddr", local->inet->host, &error_abort);
+ qemu_opt_set(opts, "localport", local->inet->port, &error_abort);
}
fd = inet_dgram_opts(opts, errp);
break;
diff --git a/util/qemu-thread-posix.c b/util/qemu-thread-posix.c
index d05a6497e..ba67cec62 100644
--- a/util/qemu-thread-posix.c
+++ b/util/qemu-thread-posix.c
@@ -26,6 +26,7 @@
#endif
#include "qemu/thread.h"
#include "qemu/atomic.h"
+#include "qemu/notify.h"
static bool name_threads;
@@ -50,12 +51,8 @@ static void error_exit(int err, const char *msg)
void qemu_mutex_init(QemuMutex *mutex)
{
int err;
- pthread_mutexattr_t mutexattr;
- pthread_mutexattr_init(&mutexattr);
- pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_ERRORCHECK);
- err = pthread_mutex_init(&mutex->lock, &mutexattr);
- pthread_mutexattr_destroy(&mutexattr);
+ err = pthread_mutex_init(&mutex->lock, NULL);
if (err)
error_exit(err, __func__);
}
@@ -306,11 +303,13 @@ static inline void futex_wait(QemuEvent *ev, unsigned val)
#else
static inline void futex_wake(QemuEvent *ev, int n)
{
+ pthread_mutex_lock(&ev->lock);
if (n == 1) {
pthread_cond_signal(&ev->cond);
} else {
pthread_cond_broadcast(&ev->cond);
}
+ pthread_mutex_unlock(&ev->lock);
}
static inline void futex_wait(QemuEvent *ev, unsigned val)
@@ -401,6 +400,42 @@ void qemu_event_wait(QemuEvent *ev)
}
}
+static pthread_key_t exit_key;
+
+union NotifierThreadData {
+ void *ptr;
+ NotifierList list;
+};
+QEMU_BUILD_BUG_ON(sizeof(union NotifierThreadData) != sizeof(void *));
+
+void qemu_thread_atexit_add(Notifier *notifier)
+{
+ union NotifierThreadData ntd;
+ ntd.ptr = pthread_getspecific(exit_key);
+ notifier_list_add(&ntd.list, notifier);
+ pthread_setspecific(exit_key, ntd.ptr);
+}
+
+void qemu_thread_atexit_remove(Notifier *notifier)
+{
+ union NotifierThreadData ntd;
+ ntd.ptr = pthread_getspecific(exit_key);
+ notifier_remove(notifier);
+ pthread_setspecific(exit_key, ntd.ptr);
+}
+
+static void qemu_thread_atexit_run(void *arg)
+{
+ union NotifierThreadData ntd = { .ptr = arg };
+ notifier_list_notify(&ntd.list, NULL);
+}
+
+static void __attribute__((constructor)) qemu_thread_atexit_init(void)
+{
+ pthread_key_create(&exit_key, qemu_thread_atexit_run);
+}
+
+
/* Attempt to set the threads name; note that this is for debug, so
* we're not going to fail if we can't set it.
*/
diff --git a/util/qemu-thread-win32.c b/util/qemu-thread-win32.c
index c405c9bef..406b52f91 100644
--- a/util/qemu-thread-win32.c
+++ b/util/qemu-thread-win32.c
@@ -12,6 +12,7 @@
*/
#include "qemu-common.h"
#include "qemu/thread.h"
+#include "qemu/notify.h"
#include <process.h>
#include <assert.h>
#include <limits.h>
@@ -268,6 +269,7 @@ struct QemuThreadData {
void *(*start_routine)(void *);
void *arg;
short mode;
+ NotifierList exit;
/* Only used for joinable threads. */
bool exited;
@@ -275,18 +277,40 @@ struct QemuThreadData {
CRITICAL_SECTION cs;
};
+static bool atexit_registered;
+static NotifierList main_thread_exit;
+
static __thread QemuThreadData *qemu_thread_data;
+static void run_main_thread_exit(void)
+{
+ notifier_list_notify(&main_thread_exit, NULL);
+}
+
+void qemu_thread_atexit_add(Notifier *notifier)
+{
+ if (!qemu_thread_data) {
+ if (!atexit_registered) {
+ atexit_registered = true;
+ atexit(run_main_thread_exit);
+ }
+ notifier_list_add(&main_thread_exit, notifier);
+ } else {
+ notifier_list_add(&qemu_thread_data->exit, notifier);
+ }
+}
+
+void qemu_thread_atexit_remove(Notifier *notifier)
+{
+ notifier_remove(notifier);
+}
+
static unsigned __stdcall win32_start_routine(void *arg)
{
QemuThreadData *data = (QemuThreadData *) arg;
void *(*start_routine)(void *) = data->start_routine;
void *thread_arg = data->arg;
- if (data->mode == QEMU_THREAD_DETACHED) {
- g_free(data);
- data = NULL;
- }
qemu_thread_data = data;
qemu_thread_exit(start_routine(thread_arg));
abort();
@@ -296,12 +320,14 @@ void qemu_thread_exit(void *arg)
{
QemuThreadData *data = qemu_thread_data;
- if (data) {
- assert(data->mode != QEMU_THREAD_DETACHED);
+ notifier_list_notify(&data->exit, NULL);
+ if (data->mode == QEMU_THREAD_JOINABLE) {
data->ret = arg;
EnterCriticalSection(&data->cs);
data->exited = true;
LeaveCriticalSection(&data->cs);
+ } else {
+ g_free(data);
}
_endthreadex(0);
}
@@ -313,9 +339,10 @@ void *qemu_thread_join(QemuThread *thread)
HANDLE handle;
data = thread->data;
- if (!data) {
+ if (data->mode == QEMU_THREAD_DETACHED) {
return NULL;
}
+
/*
* Because multiple copies of the QemuThread can exist via
* qemu_thread_get_self, we need to store a value that cannot
@@ -329,7 +356,6 @@ void *qemu_thread_join(QemuThread *thread)
CloseHandle(handle);
}
ret = data->ret;
- assert(data->mode != QEMU_THREAD_DETACHED);
DeleteCriticalSection(&data->cs);
g_free(data);
return ret;
@@ -347,6 +373,7 @@ void qemu_thread_create(QemuThread *thread, const char *name,
data->arg = arg;
data->mode = mode;
data->exited = false;
+ notifier_list_init(&data->exit);
if (data->mode != QEMU_THREAD_DETACHED) {
InitializeCriticalSection(&data->cs);
@@ -358,7 +385,7 @@ void qemu_thread_create(QemuThread *thread, const char *name,
error_exit(GetLastError(), __func__);
}
CloseHandle(hThread);
- thread->data = (mode == QEMU_THREAD_DETACHED) ? NULL : data;
+ thread->data = data;
}
void qemu_thread_get_self(QemuThread *thread)
@@ -373,11 +400,10 @@ HANDLE qemu_thread_get_handle(QemuThread *thread)
HANDLE handle;
data = thread->data;
- if (!data) {
+ if (data->mode == QEMU_THREAD_DETACHED) {
return NULL;
}
- assert(data->mode != QEMU_THREAD_DETACHED);
EnterCriticalSection(&data->cs);
if (!data->exited) {
handle = OpenThread(SYNCHRONIZE | THREAD_SUSPEND_RESUME, FALSE,
diff --git a/util/rcu.c b/util/rcu.c
new file mode 100644
index 000000000..7270151be
--- /dev/null
+++ b/util/rcu.c
@@ -0,0 +1,328 @@
+/*
+ * urcu-mb.c
+ *
+ * Userspace RCU library with explicit memory barriers
+ *
+ * Copyright (c) 2009 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright (c) 2009 Paul E. McKenney, IBM Corporation.
+ * Copyright 2015 Red Hat, Inc.
+ *
+ * Ported to QEMU by Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * IBM's contributions to this file may be relicensed under LGPLv2 or later.
+ */
+
+#include "qemu-common.h"
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+#include "qemu/rcu.h"
+#include "qemu/atomic.h"
+#include "qemu/thread.h"
+#include "qemu/main-loop.h"
+
+/*
+ * Global grace period counter. Bit 0 is always one in rcu_gp_ctr.
+ * Bits 1 and above are defined in synchronize_rcu.
+ */
+#define RCU_GP_LOCKED (1UL << 0)
+#define RCU_GP_CTR (1UL << 1)
+
+unsigned long rcu_gp_ctr = RCU_GP_LOCKED;
+
+QemuEvent rcu_gp_event;
+static QemuMutex rcu_gp_lock;
+
+/*
+ * Check whether a quiescent state was crossed between the beginning of
+ * update_counter_and_wait and now.
+ */
+static inline int rcu_gp_ongoing(unsigned long *ctr)
+{
+ unsigned long v;
+
+ v = atomic_read(ctr);
+ return v && (v != rcu_gp_ctr);
+}
+
+/* Written to only by each individual reader. Read by both the reader and the
+ * writers.
+ */
+__thread struct rcu_reader_data rcu_reader;
+
+/* Protected by rcu_gp_lock. */
+typedef QLIST_HEAD(, rcu_reader_data) ThreadList;
+static ThreadList registry = QLIST_HEAD_INITIALIZER(registry);
+
+/* Wait for previous parity/grace period to be empty of readers. */
+static void wait_for_readers(void)
+{
+ ThreadList qsreaders = QLIST_HEAD_INITIALIZER(qsreaders);
+ struct rcu_reader_data *index, *tmp;
+
+ for (;;) {
+ /* We want to be notified of changes made to rcu_gp_ongoing
+ * while we walk the list.
+ */
+ qemu_event_reset(&rcu_gp_event);
+
+ /* Instead of using atomic_mb_set for index->waiting, and
+ * atomic_mb_read for index->ctr, memory barriers are placed
+ * manually since writes to different threads are independent.
+ * atomic_mb_set has a smp_wmb before...
+ */
+ smp_wmb();
+ QLIST_FOREACH(index, &registry, node) {
+ atomic_set(&index->waiting, true);
+ }
+
+ /* ... and a smp_mb after. */
+ smp_mb();
+
+ QLIST_FOREACH_SAFE(index, &registry, node, tmp) {
+ if (!rcu_gp_ongoing(&index->ctr)) {
+ QLIST_REMOVE(index, node);
+ QLIST_INSERT_HEAD(&qsreaders, index, node);
+
+ /* No need for mb_set here, worst of all we
+ * get some extra futex wakeups.
+ */
+ atomic_set(&index->waiting, false);
+ }
+ }
+
+ /* atomic_mb_read has smp_rmb after. */
+ smp_rmb();
+
+ if (QLIST_EMPTY(&registry)) {
+ break;
+ }
+
+ /* Wait for one thread to report a quiescent state and
+ * try again.
+ */
+ qemu_event_wait(&rcu_gp_event);
+ }
+
+ /* put back the reader list in the registry */
+ QLIST_SWAP(&registry, &qsreaders, node);
+}
+
+void synchronize_rcu(void)
+{
+ qemu_mutex_lock(&rcu_gp_lock);
+
+ if (!QLIST_EMPTY(&registry)) {
+ /* In either case, the atomic_mb_set below blocks stores that free
+ * old RCU-protected pointers.
+ */
+ if (sizeof(rcu_gp_ctr) < 8) {
+ /* For architectures with 32-bit longs, a two-subphases algorithm
+ * ensures we do not encounter overflow bugs.
+ *
+ * Switch parity: 0 -> 1, 1 -> 0.
+ */
+ atomic_mb_set(&rcu_gp_ctr, rcu_gp_ctr ^ RCU_GP_CTR);
+ wait_for_readers();
+ atomic_mb_set(&rcu_gp_ctr, rcu_gp_ctr ^ RCU_GP_CTR);
+ } else {
+ /* Increment current grace period. */
+ atomic_mb_set(&rcu_gp_ctr, rcu_gp_ctr + RCU_GP_CTR);
+ }
+
+ wait_for_readers();
+ }
+
+ qemu_mutex_unlock(&rcu_gp_lock);
+}
+
+
+#define RCU_CALL_MIN_SIZE 30
+
+/* Multi-producer, single-consumer queue based on urcu/static/wfqueue.h
+ * from liburcu. Note that head is only used by the consumer.
+ */
+static struct rcu_head dummy;
+static struct rcu_head *head = &dummy, **tail = &dummy.next;
+static int rcu_call_count;
+static QemuEvent rcu_call_ready_event;
+
+static void enqueue(struct rcu_head *node)
+{
+ struct rcu_head **old_tail;
+
+ node->next = NULL;
+ old_tail = atomic_xchg(&tail, &node->next);
+ atomic_mb_set(old_tail, node);
+}
+
+static struct rcu_head *try_dequeue(void)
+{
+ struct rcu_head *node, *next;
+
+retry:
+ /* Test for an empty list, which we do not expect. Note that for
+ * the consumer head and tail are always consistent. The head
+ * is consistent because only the consumer reads/writes it.
+ * The tail, because it is the first step in the enqueuing.
+ * It is only the next pointers that might be inconsistent.
+ */
+ if (head == &dummy && atomic_mb_read(&tail) == &dummy.next) {
+ abort();
+ }
+
+ /* If the head node has NULL in its next pointer, the value is
+ * wrong and we need to wait until its enqueuer finishes the update.
+ */
+ node = head;
+ next = atomic_mb_read(&head->next);
+ if (!next) {
+ return NULL;
+ }
+
+ /* Since we are the sole consumer, and we excluded the empty case
+ * above, the queue will always have at least two nodes: the
+ * dummy node, and the one being removed. So we do not need to update
+ * the tail pointer.
+ */
+ head = next;
+
+ /* If we dequeued the dummy node, add it back at the end and retry. */
+ if (node == &dummy) {
+ enqueue(node);
+ goto retry;
+ }
+
+ return node;
+}
+
+static void *call_rcu_thread(void *opaque)
+{
+ struct rcu_head *node;
+
+ for (;;) {
+ int tries = 0;
+ int n = atomic_read(&rcu_call_count);
+
+ /* Heuristically wait for a decent number of callbacks to pile up.
+ * Fetch rcu_call_count now, we only must process elements that were
+ * added before synchronize_rcu() starts.
+ */
+ while (n == 0 || (n < RCU_CALL_MIN_SIZE && ++tries <= 5)) {
+ g_usleep(10000);
+ if (n == 0) {
+ qemu_event_reset(&rcu_call_ready_event);
+ n = atomic_read(&rcu_call_count);
+ if (n == 0) {
+ qemu_event_wait(&rcu_call_ready_event);
+ }
+ }
+ n = atomic_read(&rcu_call_count);
+ }
+
+ atomic_sub(&rcu_call_count, n);
+ synchronize_rcu();
+ qemu_mutex_lock_iothread();
+ while (n > 0) {
+ node = try_dequeue();
+ while (!node) {
+ qemu_mutex_unlock_iothread();
+ qemu_event_reset(&rcu_call_ready_event);
+ node = try_dequeue();
+ if (!node) {
+ qemu_event_wait(&rcu_call_ready_event);
+ node = try_dequeue();
+ }
+ qemu_mutex_lock_iothread();
+ }
+
+ n--;
+ node->func(node);
+ }
+ qemu_mutex_unlock_iothread();
+ }
+ abort();
+}
+
+void call_rcu1(struct rcu_head *node, void (*func)(struct rcu_head *node))
+{
+ node->func = func;
+ enqueue(node);
+ atomic_inc(&rcu_call_count);
+ qemu_event_set(&rcu_call_ready_event);
+}
+
+void rcu_register_thread(void)
+{
+ assert(rcu_reader.ctr == 0);
+ qemu_mutex_lock(&rcu_gp_lock);
+ QLIST_INSERT_HEAD(&registry, &rcu_reader, node);
+ qemu_mutex_unlock(&rcu_gp_lock);
+}
+
+void rcu_unregister_thread(void)
+{
+ qemu_mutex_lock(&rcu_gp_lock);
+ QLIST_REMOVE(&rcu_reader, node);
+ qemu_mutex_unlock(&rcu_gp_lock);
+}
+
+static void rcu_init_complete(void)
+{
+ QemuThread thread;
+
+ qemu_mutex_init(&rcu_gp_lock);
+ qemu_event_init(&rcu_gp_event, true);
+
+ qemu_event_init(&rcu_call_ready_event, false);
+
+ /* The caller is assumed to have iothread lock, so the call_rcu thread
+ * must have been quiescent even after forking, just recreate it.
+ */
+ qemu_thread_create(&thread, "call_rcu", call_rcu_thread,
+ NULL, QEMU_THREAD_DETACHED);
+
+ rcu_register_thread();
+}
+
+#ifdef CONFIG_POSIX
+static void rcu_init_lock(void)
+{
+ qemu_mutex_lock(&rcu_gp_lock);
+}
+
+static void rcu_init_unlock(void)
+{
+ qemu_mutex_unlock(&rcu_gp_lock);
+}
+#endif
+
+void rcu_after_fork(void)
+{
+ memset(&registry, 0, sizeof(registry));
+ rcu_init_complete();
+}
+
+static void __attribute__((__constructor__)) rcu_init(void)
+{
+#ifdef CONFIG_POSIX
+ pthread_atfork(rcu_init_lock, rcu_init_unlock, rcu_init_unlock);
+#endif
+ rcu_init_complete();
+}
diff --git a/util/uri.c b/util/uri.c
index e348c1768..550b98458 100644
--- a/util/uri.c
+++ b/util/uri.c
@@ -225,7 +225,7 @@ rfc3986_parse_scheme(URI *uri, const char **str) {
while (ISA_ALPHA(cur) || ISA_DIGIT(cur) ||
(*cur == '+') || (*cur == '-') || (*cur == '.')) cur++;
if (uri != NULL) {
- if (uri->scheme != NULL) g_free(uri->scheme);
+ g_free(uri->scheme);
uri->scheme = g_strndup(*str, cur - *str);
}
*str = cur;
@@ -262,8 +262,7 @@ rfc3986_parse_fragment(URI *uri, const char **str)
((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
NEXT(cur);
if (uri != NULL) {
- if (uri->fragment != NULL)
- g_free(uri->fragment);
+ g_free(uri->fragment);
if (uri->cleanup & 2)
uri->fragment = g_strndup(*str, cur - *str);
else
@@ -298,8 +297,7 @@ rfc3986_parse_query(URI *uri, const char **str)
((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
NEXT(cur);
if (uri != NULL) {
- if (uri->query != NULL)
- g_free (uri->query);
+ g_free(uri->query);
uri->query = g_strndup (*str, cur - *str);
}
*str = cur;
@@ -322,19 +320,23 @@ static int
rfc3986_parse_port(URI *uri, const char **str)
{
const char *cur = *str;
+ int port = 0;
if (ISA_DIGIT(cur)) {
- if (uri != NULL)
- uri->port = 0;
- while (ISA_DIGIT(cur)) {
- if (uri != NULL)
- uri->port = uri->port * 10 + (*cur - '0');
- cur++;
- }
- *str = cur;
- return(0);
+ while (ISA_DIGIT(cur)) {
+ port = port * 10 + (*cur - '0');
+ if (port > 65535) {
+ return 1;
+ }
+ cur++;
+ }
+ if (uri) {
+ uri->port = port;
+ }
+ *str = cur;
+ return 0;
}
- return(1);
+ return 1;
}
/**
@@ -360,7 +362,7 @@ rfc3986_parse_user_info(URI *uri, const char **str)
NEXT(cur);
if (*cur == '@') {
if (uri != NULL) {
- if (uri->user != NULL) g_free(uri->user);
+ g_free(uri->user);
if (uri->cleanup & 2)
uri->user = g_strndup(*str, cur - *str);
else
@@ -473,9 +475,9 @@ not_ipv4:
NEXT(cur);
found:
if (uri != NULL) {
- if (uri->authority != NULL) g_free(uri->authority);
+ g_free(uri->authority);
uri->authority = NULL;
- if (uri->server != NULL) g_free(uri->server);
+ g_free(uri->server);
if (cur != host) {
if (uri->cleanup & 2)
uri->server = g_strndup(host, cur - host);
@@ -585,7 +587,7 @@ rfc3986_parse_path_ab_empty(URI *uri, const char **str)
if (ret != 0) return(ret);
}
if (uri != NULL) {
- if (uri->path != NULL) g_free(uri->path);
+ g_free(uri->path);
if (*str != cur) {
if (uri->cleanup & 2)
uri->path = g_strndup(*str, cur - *str);
@@ -631,7 +633,7 @@ rfc3986_parse_path_absolute(URI *uri, const char **str)
}
}
if (uri != NULL) {
- if (uri->path != NULL) g_free(uri->path);
+ g_free(uri->path);
if (cur != *str) {
if (uri->cleanup & 2)
uri->path = g_strndup(*str, cur - *str);
@@ -673,7 +675,7 @@ rfc3986_parse_path_rootless(URI *uri, const char **str)
if (ret != 0) return(ret);
}
if (uri != NULL) {
- if (uri->path != NULL) g_free(uri->path);
+ g_free(uri->path);
if (cur != *str) {
if (uri->cleanup & 2)
uri->path = g_strndup(*str, cur - *str);
@@ -715,7 +717,7 @@ rfc3986_parse_path_no_scheme(URI *uri, const char **str)
if (ret != 0) return(ret);
}
if (uri != NULL) {
- if (uri->path != NULL) g_free(uri->path);
+ g_free(uri->path);
if (cur != *str) {
if (uri->cleanup & 2)
uri->path = g_strndup(*str, cur - *str);
@@ -769,7 +771,7 @@ rfc3986_parse_hier_part(URI *uri, const char **str)
} else {
/* path-empty is effectively empty */
if (uri != NULL) {
- if (uri->path != NULL) g_free(uri->path);
+ g_free(uri->path);
uri->path = NULL;
}
}
@@ -812,7 +814,7 @@ rfc3986_parse_relative_ref(URI *uri, const char *str) {
} else {
/* path-empty is effectively empty */
if (uri != NULL) {
- if (uri->path != NULL) g_free(uri->path);
+ g_free(uri->path);
uri->path = NULL;
}
}
@@ -930,12 +932,10 @@ uri_parse(const char *str) {
if (str == NULL)
return(NULL);
uri = uri_new();
- if (uri != NULL) {
- ret = rfc3986_parse_uri_reference(uri, str);
- if (ret) {
- uri_free(uri);
- return(NULL);
- }
+ ret = rfc3986_parse_uri_reference(uri, str);
+ if (ret) {
+ uri_free(uri);
+ return(NULL);
}
return(uri);
}
@@ -976,15 +976,13 @@ uri_parse_raw(const char *str, int raw) {
if (str == NULL)
return(NULL);
uri = uri_new();
- if (uri != NULL) {
- if (raw) {
- uri->cleanup |= 2;
- }
- ret = uri_parse_into(uri, str);
- if (ret) {
- uri_free(uri);
- return(NULL);
- }
+ if (raw) {
+ uri->cleanup |= 2;
+ }
+ ret = uri_parse_into(uri, str);
+ if (ret) {
+ uri_free(uri);
+ return(NULL);
}
return(uri);
}
@@ -1006,8 +1004,7 @@ URI *
uri_new(void) {
URI *ret;
- ret = (URI *) g_malloc(sizeof(URI));
- memset(ret, 0, sizeof(URI));
+ ret = g_new0(URI, 1);
return(ret);
}
@@ -1056,14 +1053,12 @@ uri_to_string(URI *uri) {
while (*p != 0) {
if (len >= max) {
temp = realloc2n(ret, &max);
- if (temp == NULL) goto mem_error;
ret = temp;
}
ret[len++] = *p++;
}
if (len >= max) {
temp = realloc2n(ret, &max);
- if (temp == NULL) goto mem_error;
ret = temp;
}
ret[len++] = ':';
@@ -1073,7 +1068,6 @@ uri_to_string(URI *uri) {
while (*p != 0) {
if (len + 3 >= max) {
temp = realloc2n(ret, &max);
- if (temp == NULL) goto mem_error;
ret = temp;
}
if (IS_RESERVED(*(p)) || IS_UNRESERVED(*(p)))
@@ -1090,7 +1084,6 @@ uri_to_string(URI *uri) {
if (uri->server != NULL) {
if (len + 3 >= max) {
temp = realloc2n(ret, &max);
- if (temp == NULL) goto mem_error;
ret = temp;
}
ret[len++] = '/';
@@ -1100,7 +1093,6 @@ uri_to_string(URI *uri) {
while (*p != 0) {
if (len + 3 >= max) {
temp = realloc2n(ret, &max);
- if (temp == NULL) goto mem_error;
ret = temp;
}
if ((IS_UNRESERVED(*(p))) ||
@@ -1119,7 +1111,6 @@ uri_to_string(URI *uri) {
}
if (len + 3 >= max) {
temp = realloc2n(ret, &max);
- if (temp == NULL) goto mem_error;
ret = temp;
}
ret[len++] = '@';
@@ -1128,7 +1119,6 @@ uri_to_string(URI *uri) {
while (*p != 0) {
if (len >= max) {
temp = realloc2n(ret, &max);
- if (temp == NULL) goto mem_error;
ret = temp;
}
ret[len++] = *p++;
@@ -1136,7 +1126,6 @@ uri_to_string(URI *uri) {
if (uri->port > 0) {
if (len + 10 >= max) {
temp = realloc2n(ret, &max);
- if (temp == NULL) goto mem_error;
ret = temp;
}
len += snprintf(&ret[len], max - len, ":%d", uri->port);
@@ -1144,7 +1133,6 @@ uri_to_string(URI *uri) {
} else if (uri->authority != NULL) {
if (len + 3 >= max) {
temp = realloc2n(ret, &max);
- if (temp == NULL) goto mem_error;
ret = temp;
}
ret[len++] = '/';
@@ -1153,7 +1141,6 @@ uri_to_string(URI *uri) {
while (*p != 0) {
if (len + 3 >= max) {
temp = realloc2n(ret, &max);
- if (temp == NULL) goto mem_error;
ret = temp;
}
if ((IS_UNRESERVED(*(p))) ||
@@ -1172,7 +1159,6 @@ uri_to_string(URI *uri) {
} else if (uri->scheme != NULL) {
if (len + 3 >= max) {
temp = realloc2n(ret, &max);
- if (temp == NULL) goto mem_error;
ret = temp;
}
ret[len++] = '/';
@@ -1192,7 +1178,6 @@ uri_to_string(URI *uri) {
(!strcmp(uri->scheme, "file"))) {
if (len + 3 >= max) {
temp = realloc2n(ret, &max);
- if (temp == NULL) goto mem_error;
ret = temp;
}
ret[len++] = *p++;
@@ -1202,7 +1187,6 @@ uri_to_string(URI *uri) {
while (*p != 0) {
if (len + 3 >= max) {
temp = realloc2n(ret, &max);
- if (temp == NULL) goto mem_error;
ret = temp;
}
if ((IS_UNRESERVED(*(p))) || ((*(p) == '/')) ||
@@ -1222,7 +1206,6 @@ uri_to_string(URI *uri) {
if (uri->query != NULL) {
if (len + 1 >= max) {
temp = realloc2n(ret, &max);
- if (temp == NULL) goto mem_error;
ret = temp;
}
ret[len++] = '?';
@@ -1230,7 +1213,6 @@ uri_to_string(URI *uri) {
while (*p != 0) {
if (len + 1 >= max) {
temp = realloc2n(ret, &max);
- if (temp == NULL) goto mem_error;
ret = temp;
}
ret[len++] = *p++;
@@ -1240,7 +1222,6 @@ uri_to_string(URI *uri) {
if (uri->fragment != NULL) {
if (len + 3 >= max) {
temp = realloc2n(ret, &max);
- if (temp == NULL) goto mem_error;
ret = temp;
}
ret[len++] = '#';
@@ -1248,7 +1229,6 @@ uri_to_string(URI *uri) {
while (*p != 0) {
if (len + 3 >= max) {
temp = realloc2n(ret, &max);
- if (temp == NULL) goto mem_error;
ret = temp;
}
if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p))))
@@ -1264,15 +1244,10 @@ uri_to_string(URI *uri) {
}
if (len >= max) {
temp = realloc2n(ret, &max);
- if (temp == NULL) goto mem_error;
ret = temp;
}
ret[len] = 0;
return(ret);
-
-mem_error:
- g_free(ret);
- return(NULL);
}
/**
@@ -1285,21 +1260,21 @@ static void
uri_clean(URI *uri) {
if (uri == NULL) return;
- if (uri->scheme != NULL) g_free(uri->scheme);
+ g_free(uri->scheme);
uri->scheme = NULL;
- if (uri->server != NULL) g_free(uri->server);
+ g_free(uri->server);
uri->server = NULL;
- if (uri->user != NULL) g_free(uri->user);
+ g_free(uri->user);
uri->user = NULL;
- if (uri->path != NULL) g_free(uri->path);
+ g_free(uri->path);
uri->path = NULL;
- if (uri->fragment != NULL) g_free(uri->fragment);
+ g_free(uri->fragment);
uri->fragment = NULL;
- if (uri->opaque != NULL) g_free(uri->opaque);
+ g_free(uri->opaque);
uri->opaque = NULL;
- if (uri->authority != NULL) g_free(uri->authority);
+ g_free(uri->authority);
uri->authority = NULL;
- if (uri->query != NULL) g_free(uri->query);
+ g_free(uri->query);
uri->query = NULL;
}
@@ -1678,8 +1653,6 @@ uri_resolve(const char *uri, const char *base) {
else {
if (*uri) {
ref = uri_new();
- if (ref == NULL)
- goto done;
ret = uri_parse_into(ref, uri);
}
else
@@ -1698,8 +1671,6 @@ uri_resolve(const char *uri, const char *base) {
ret = -1;
else {
bas = uri_new();
- if (bas == NULL)
- goto done;
ret = uri_parse_into(bas, base);
}
if (ret != 0) {
@@ -1711,10 +1682,8 @@ uri_resolve(const char *uri, const char *base) {
/*
* the base fragment must be ignored
*/
- if (bas->fragment != NULL) {
- g_free(bas->fragment);
- bas->fragment = NULL;
- }
+ g_free(bas->fragment);
+ bas->fragment = NULL;
val = uri_to_string(bas);
goto done;
}
@@ -1732,28 +1701,23 @@ uri_resolve(const char *uri, const char *base) {
* document.
*/
res = uri_new();
- if (res == NULL)
- goto done;
if ((ref->scheme == NULL) && (ref->path == NULL) &&
((ref->authority == NULL) && (ref->server == NULL))) {
- if (bas->scheme != NULL)
- res->scheme = g_strdup(bas->scheme);
+ res->scheme = g_strdup(bas->scheme);
if (bas->authority != NULL)
res->authority = g_strdup(bas->authority);
else if (bas->server != NULL) {
- res->server = g_strdup(bas->server);
- if (bas->user != NULL)
- res->user = g_strdup(bas->user);
- res->port = bas->port;
+ res->server = g_strdup(bas->server);
+ res->user = g_strdup(bas->user);
+ res->port = bas->port;
}
- if (bas->path != NULL)
- res->path = g_strdup(bas->path);
- if (ref->query != NULL)
+ res->path = g_strdup(bas->path);
+ if (ref->query != NULL) {
res->query = g_strdup (ref->query);
- else if (bas->query != NULL)
- res->query = g_strdup(bas->query);
- if (ref->fragment != NULL)
- res->fragment = g_strdup(ref->fragment);
+ } else {
+ res->query = g_strdup(bas->query);
+ }
+ res->fragment = g_strdup(ref->fragment);
goto step_7;
}
@@ -1767,13 +1731,10 @@ uri_resolve(const char *uri, const char *base) {
val = uri_to_string(ref);
goto done;
}
- if (bas->scheme != NULL)
- res->scheme = g_strdup(bas->scheme);
+ res->scheme = g_strdup(bas->scheme);
- if (ref->query != NULL)
- res->query = g_strdup(ref->query);
- if (ref->fragment != NULL)
- res->fragment = g_strdup(ref->fragment);
+ res->query = g_strdup(ref->query);
+ res->fragment = g_strdup(ref->fragment);
/*
* 4) If the authority component is defined, then the reference is a
@@ -1787,20 +1748,17 @@ uri_resolve(const char *uri, const char *base) {
res->authority = g_strdup(ref->authority);
else {
res->server = g_strdup(ref->server);
- if (ref->user != NULL)
- res->user = g_strdup(ref->user);
+ res->user = g_strdup(ref->user);
res->port = ref->port;
}
- if (ref->path != NULL)
- res->path = g_strdup(ref->path);
+ res->path = g_strdup(ref->path);
goto step_7;
}
if (bas->authority != NULL)
res->authority = g_strdup(bas->authority);
else if (bas->server != NULL) {
- res->server = g_strdup(bas->server);
- if (bas->user != NULL)
- res->user = g_strdup(bas->user);
+ res->server = g_strdup(bas->server);
+ res->user = g_strdup(bas->user);
res->port = bas->port;
}
@@ -1947,8 +1905,6 @@ uri_resolve_relative (const char *uri, const char * base)
* First parse URI into a standard form
*/
ref = uri_new ();
- if (ref == NULL)
- return NULL;
/* If URI not already in "relative" form */
if (uri[0] != '.') {
ret = uri_parse_into (ref, uri);
@@ -1965,8 +1921,6 @@ uri_resolve_relative (const char *uri, const char * base)
goto done;
}
bas = uri_new ();
- if (bas == NULL)
- goto done;
if (base[0] != '.') {
ret = uri_parse_into (bas, base);
if (ret != 0)
@@ -1985,7 +1939,8 @@ uri_resolve_relative (const char *uri, const char * base)
val = g_strdup (uri);
goto done;
}
- if (!strcmp(bas->path, ref->path)) {
+ if (bas->path == ref->path ||
+ (bas->path && ref->path && !strcmp(bas->path, ref->path))) {
val = g_strdup("");
goto done;
}