#include "sysemu/sysemu.h"
#include "qemu/config-file.h"
#include "qemu/error-report.h"
+#include "qemu/qemu-print.h"
#include "chardev/char.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-char.h"
#include "qapi/qmp/qerror.h"
#include "sysemu/replay.h"
#include "qemu/help_option.h"
+#include "qemu/module.h"
#include "qemu/option.h"
+#include "qemu/id.h"
+#include "qemu/coroutine.h"
#include "chardev/char-mux.h"
return container_get(object_get_root(), "/chardevs");
}
-static void chr_be_event(Chardev *s, int event)
+static void chr_be_event(Chardev *s, QEMUChrEvent event)
{
CharBackend *be = s->be;
be->chr_event(be->opaque, event);
}
-void qemu_chr_be_event(Chardev *s, int event)
+void qemu_chr_be_event(Chardev *s, QEMUChrEvent event)
{
/* Keep track if the char device is open */
switch (event) {
case CHR_EVENT_CLOSED:
s->be_open = 0;
break;
+ case CHR_EVENT_BREAK:
+ case CHR_EVENT_MUX_IN:
+ case CHR_EVENT_MUX_OUT:
+ /* Ignore */
+ break;
}
CHARDEV_GET_CLASS(s)->chr_be_event(s, event);
retry:
res = cc->chr_write(s, buf + *offset, len - *offset);
if (res < 0 && errno == EAGAIN && write_all) {
- g_usleep(100);
+ if (qemu_in_coroutine()) {
+ qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000);
+ } else {
+ g_usleep(100);
+ }
goto retry;
}
{
ChardevClass *cc = CHARDEV_GET_CLASS(s);
+ assert(qemu_chr_has_feature(s, QEMU_CHAR_FEATURE_GCONTEXT)
+ || !context);
s->gcontext = context;
if (cc->chr_update_read_handler) {
cc->chr_update_read_handler(s);
chr->logfd = -1;
qemu_mutex_init(&chr->chr_write_lock);
+
+ /*
+ * Assume if chr_update_read_handler is implemented it will
+ * take the updated gcontext into account.
+ */
+ if (CHARDEV_GET_CLASS(chr)->chr_update_read_handler) {
+ qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT);
+ }
+
}
static int null_chr_write(Chardev *chr, const uint8_t *buf, int len)
return opts;
}
+ error_report("'%s' is not a valid char driver", filename);
+
fail:
qemu_opts_del(opts);
return NULL;
{
GString *str = opaque;
- g_string_append_printf(str, "\n%s", name);
+ g_string_append_printf(str, "\n %s", name);
}
static const char *chardev_alias_translate(const char *name)
return backend;
}
-Chardev *qemu_chr_new_from_opts(QemuOpts *opts, Error **errp)
+Chardev *qemu_chr_new_from_opts(QemuOpts *opts, GMainContext *context,
+ Error **errp)
{
const ChardevClass *cc;
Chardev *chr = NULL;
chardev_name_foreach(help_string_append, str);
- error_printf("Available chardev backend types: %s\n", str->str);
+ qemu_printf("Available chardev backend types: %s\n", str->str);
g_string_free(str, true);
return NULL;
}
chr = qemu_chardev_new(bid ? bid : id,
object_class_get_name(OBJECT_CLASS(cc)),
- backend, errp);
+ backend, context, errp);
if (chr == NULL) {
goto out;
backend->type = CHARDEV_BACKEND_KIND_MUX;
backend->u.mux.data = g_new0(ChardevMux, 1);
backend->u.mux.data->chardev = g_strdup(bid);
- mux = qemu_chardev_new(id, TYPE_CHARDEV_MUX, backend, errp);
+ mux = qemu_chardev_new(id, TYPE_CHARDEV_MUX, backend, context, errp);
if (mux == NULL) {
object_unparent(OBJECT(chr));
chr = NULL;
}
Chardev *qemu_chr_new_noreplay(const char *label, const char *filename,
- bool permit_mux_mon)
+ bool permit_mux_mon, GMainContext *context)
{
const char *p;
Chardev *chr;
if (!opts)
return NULL;
- chr = qemu_chr_new_from_opts(opts, &err);
+ chr = qemu_chr_new_from_opts(opts, context, &err);
if (!chr) {
error_report_err(err);
goto out;
if (qemu_opt_get_bool(opts, "mux", 0)) {
assert(permit_mux_mon);
- monitor_init(chr, MONITOR_USE_READLINE);
+ monitor_init_hmp(chr, true, &err);
+ if (err) {
+ error_report_err(err);
+ object_unparent(OBJECT(chr));
+ chr = NULL;
+ goto out;
+ }
}
out:
static Chardev *qemu_chr_new_permit_mux_mon(const char *label,
const char *filename,
- bool permit_mux_mon)
+ bool permit_mux_mon,
+ GMainContext *context)
{
Chardev *chr;
- chr = qemu_chr_new_noreplay(label, filename, permit_mux_mon);
+ chr = qemu_chr_new_noreplay(label, filename, permit_mux_mon, context);
if (chr) {
if (replay_mode != REPLAY_MODE_NONE) {
qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_REPLAY);
return chr;
}
-Chardev *qemu_chr_new(const char *label, const char *filename)
+Chardev *qemu_chr_new(const char *label, const char *filename,
+ GMainContext *context)
{
- return qemu_chr_new_permit_mux_mon(label, filename, false);
+ return qemu_chr_new_permit_mux_mon(label, filename, false, context);
}
-Chardev *qemu_chr_new_mux_mon(const char *label, const char *filename)
+Chardev *qemu_chr_new_mux_mon(const char *label, const char *filename,
+ GMainContext *context)
{
- return qemu_chr_new_permit_mux_mon(label, filename, true);
+ return qemu_chr_new_permit_mux_mon(label, filename, true, context);
}
static int qmp_query_chardev_foreach(Object *obj, void *data)
},{
.name = "tls-creds",
.type = QEMU_OPT_STRING,
+ },{
+ .name = "tls-authz",
+ .type = QEMU_OPT_STRING,
},{
.name = "websocket",
.type = QEMU_OPT_BOOL,
},{
.name = "logappend",
.type = QEMU_OPT_BOOL,
+ },{
+ .name = "tight",
+ .type = QEMU_OPT_BOOL,
+ .def_value_str = "on",
+ },{
+ .name = "abstract",
+ .type = QEMU_OPT_BOOL,
},
{ /* end of list */ }
},
return set_bit(feature, chr->features);
}
-Chardev *qemu_chardev_new(const char *id, const char *typename,
- ChardevBackend *backend,
- Error **errp)
+static Chardev *chardev_new(const char *id, const char *typename,
+ ChardevBackend *backend,
+ GMainContext *gcontext,
+ Error **errp)
{
Object *obj;
Chardev *chr = NULL;
obj = object_new(typename);
chr = CHARDEV(obj);
chr->label = g_strdup(id);
+ chr->gcontext = gcontext;
qemu_char_open(chr, backend, &be_opened, &local_err);
if (local_err) {
}
if (id) {
- object_property_add_child(get_chardevs_root(), id, obj, &local_err);
- if (local_err) {
- goto end;
- }
+ object_property_add_child(get_chardevs_root(), id, obj);
object_unref(obj);
}
return chr;
}
+Chardev *qemu_chardev_new(const char *id, const char *typename,
+ ChardevBackend *backend,
+ GMainContext *gcontext,
+ Error **errp)
+{
+ g_autofree char *genid = NULL;
+
+ if (!id) {
+ genid = id_generate(ID_CHR);
+ id = genid;
+ }
+
+ return chardev_new(id, typename, backend, gcontext, errp);
+}
+
ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
Error **errp)
{
return NULL;
}
- chr = qemu_chardev_new(id, object_class_get_name(OBJECT_CLASS(cc)),
- backend, errp);
+ chr = chardev_new(id, object_class_get_name(OBJECT_CLASS(cc)),
+ backend, NULL, errp);
if (!chr) {
return NULL;
}
return NULL;
}
- chr_new = qemu_chardev_new(NULL, object_class_get_name(OBJECT_CLASS(cc)),
- backend, errp);
+ chr_new = chardev_new(NULL, object_class_get_name(OBJECT_CLASS(cc)),
+ backend, chr->gcontext, errp);
if (!chr_new) {
return NULL;
}
object_unparent(OBJECT(chr));
object_property_add_child(get_chardevs_root(), chr_new->label,
- OBJECT(chr_new), &error_abort);
+ OBJECT(chr_new));
object_unref(OBJECT(chr_new));
ret = g_new0(ChardevReturn, 1);