aboutsummaryrefslogtreecommitdiff
path: root/qemu-char.c
diff options
context:
space:
mode:
authorMarc-André Lureau <marcandre.lureau@redhat.com>2016-12-07 18:39:10 +0300
committerPaolo Bonzini <pbonzini@redhat.com>2017-01-27 18:08:00 +0100
commit777357d758d937c9dd83082c39aff9f1e53e9ba3 (patch)
tree20b236bf5acc7dfc20b4358bb8072dfe983c0e2d /qemu-char.c
parent5bf5adaeb7245d7037f29429fb231b4b602d5b50 (diff)
chardev: qom-ify
Turn Chardev into Object. qemu_chr_alloc() is replaced by the qemu_chardev_new() constructor. It will call qemu_char_open() to open/intialize the chardev with the ChardevCommon *backend settings. The CharDriver::create() callback is turned into a ChardevClass::open() which is called from the newly introduced qemu_chardev_open(). "chardev-gdb" and "chardev-hci" are internal chardev and aren't creatable directly with -chardev. Use a new internal flag to disable them. We may want to use TYPE_USER_CREATABLE interface instead, or perhaps allow -chardev usage. Although in general we keep typename and macros private, unless the type is being used by some other file, in this patch, all types and common helper macros for qemu-char.c are in char.h. This is to help transition now (some types must be declared early, while some aren't shared) and when splitting in several units. This is to be improved later. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'qemu-char.c')
-rw-r--r--qemu-char.c1327
1 files changed, 712 insertions, 615 deletions
diff --git a/qemu-char.c b/qemu-char.c
index 113c4a859e..6b4a299702 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -160,43 +160,6 @@ static char *sockaddr_to_str(struct sockaddr_storage *ss, socklen_t ss_len,
static QTAILQ_HEAD(ChardevHead, Chardev) chardevs =
QTAILQ_HEAD_INITIALIZER(chardevs);
-static void qemu_chr_free_common(Chardev *chr);
-
-Chardev *qemu_chr_alloc(const CharDriver *driver,
- ChardevCommon *backend, Error **errp)
-{
- Chardev *chr;
-
- assert(driver);
- assert(driver->chr_write);
- assert(driver->instance_size >= sizeof(Chardev));
-
- chr = g_malloc0(driver->instance_size);
- qemu_mutex_init(&chr->chr_write_lock);
- if (backend->has_logfile) {
- int flags = O_WRONLY | O_CREAT;
- if (backend->has_logappend &&
- backend->logappend) {
- flags |= O_APPEND;
- } else {
- flags |= O_TRUNC;
- }
- chr->logfd = qemu_open(backend->logfile, flags, 0666);
- if (chr->logfd < 0) {
- error_setg_errno(errp, errno,
- "Unable to open logfile %s",
- backend->logfile);
- g_free(chr);
- return NULL;
- }
- } else {
- chr->logfd = -1;
- }
- chr->driver = driver;
-
- return chr;
-}
-
void qemu_chr_be_event(Chardev *s, int event)
{
CharBackend *be = s->be;
@@ -254,13 +217,14 @@ static void qemu_chr_fe_write_log(Chardev *s,
static int qemu_chr_fe_write_buffer(Chardev *s,
const uint8_t *buf, int len, int *offset)
{
+ ChardevClass *cc = CHARDEV_GET_CLASS(s);
int res = 0;
*offset = 0;
qemu_mutex_lock(&s->chr_write_lock);
while (*offset < len) {
retry:
- res = s->driver->chr_write(s, buf + *offset, len - *offset);
+ res = cc->chr_write(s, buf + *offset, len - *offset);
if (res < 0 && errno == EAGAIN) {
g_usleep(100);
goto retry;
@@ -288,6 +252,7 @@ static bool qemu_chr_replay(Chardev *chr)
int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len)
{
Chardev *s = be->chr;
+ ChardevClass *cc;
int ret;
if (!s) {
@@ -302,8 +267,9 @@ int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len)
return ret;
}
+ cc = CHARDEV_GET_CLASS(s);
qemu_mutex_lock(&s->chr_write_lock);
- ret = s->driver->chr_write(s, buf, len);
+ ret = cc->chr_write(s, buf, len);
if (ret > 0) {
qemu_chr_fe_write_log(s, buf, ret);
@@ -359,7 +325,7 @@ int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len)
int offset = 0, counter = 10;
int res;
- if (!s || !s->driver->chr_sync_read) {
+ if (!s || !CHARDEV_GET_CLASS(s)->chr_sync_read) {
return 0;
}
@@ -369,7 +335,8 @@ int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len)
while (offset < len) {
retry:
- res = s->driver->chr_sync_read(s, buf + offset, len - offset);
+ res = CHARDEV_GET_CLASS(s)->chr_sync_read(s, buf + offset,
+ len - offset);
if (res == -1 && errno == EAGAIN) {
g_usleep(100);
goto retry;
@@ -404,10 +371,10 @@ int qemu_chr_fe_ioctl(CharBackend *be, int cmd, void *arg)
Chardev *s = be->chr;
int res;
- if (!s || !s->driver->chr_ioctl || qemu_chr_replay(s)) {
+ if (!s || !CHARDEV_GET_CLASS(s)->chr_ioctl || qemu_chr_replay(s)) {
res = -ENOTSUP;
} else {
- res = s->driver->chr_ioctl(s, cmd, arg);
+ res = CHARDEV_GET_CLASS(s)->chr_ioctl(s, cmd, arg);
}
return res;
@@ -466,7 +433,8 @@ int qemu_chr_fe_get_msgfds(CharBackend *be, int *fds, int len)
return -1;
}
- return s->driver->get_msgfds ? s->driver->get_msgfds(s, fds, len) : -1;
+ return CHARDEV_GET_CLASS(s)->get_msgfds ?
+ CHARDEV_GET_CLASS(s)->get_msgfds(s, fds, len) : -1;
}
int qemu_chr_fe_set_msgfds(CharBackend *be, int *fds, int num)
@@ -477,12 +445,14 @@ int qemu_chr_fe_set_msgfds(CharBackend *be, int *fds, int num)
return -1;
}
- return s->driver->set_msgfds ? s->driver->set_msgfds(s, fds, num) : -1;
+ return CHARDEV_GET_CLASS(s)->set_msgfds ?
+ CHARDEV_GET_CLASS(s)->set_msgfds(s, fds, num) : -1;
}
int qemu_chr_add_client(Chardev *s, int fd)
{
- return s->driver->chr_add_client ? s->driver->chr_add_client(s, fd) : -1;
+ return CHARDEV_GET_CLASS(s)->chr_add_client ?
+ CHARDEV_GET_CLASS(s)->chr_add_client(s, fd) : -1;
}
void qemu_chr_fe_accept_input(CharBackend *be)
@@ -493,8 +463,8 @@ void qemu_chr_fe_accept_input(CharBackend *be)
return;
}
- if (s->driver->chr_accept_input) {
- s->driver->chr_accept_input(s);
+ if (CHARDEV_GET_CLASS(s)->chr_accept_input) {
+ CHARDEV_GET_CLASS(s)->chr_accept_input(s);
}
qemu_notify_event();
}
@@ -515,34 +485,98 @@ static void remove_fd_in_watch(Chardev *chr);
static void mux_chr_set_handlers(Chardev *chr, GMainContext *context);
static void mux_set_focus(Chardev *chr, int focus);
-static int null_chr_write(Chardev *chr, const uint8_t *buf, int len)
+static void qemu_char_open(Chardev *chr, ChardevBackend *backend,
+ bool *be_opened, Error **errp)
{
- return len;
+ ChardevClass *cc = CHARDEV_GET_CLASS(chr);
+ /* Any ChardevCommon member would work */
+ ChardevCommon *common = backend ? backend->u.null.data : NULL;
+
+ if (common && common->has_logfile) {
+ int flags = O_WRONLY | O_CREAT;
+ if (common->has_logappend &&
+ common->logappend) {
+ flags |= O_APPEND;
+ } else {
+ flags |= O_TRUNC;
+ }
+ chr->logfd = qemu_open(common->logfile, flags, 0666);
+ if (chr->logfd < 0) {
+ error_setg_errno(errp, errno,
+ "Unable to open logfile %s",
+ common->logfile);
+ return;
+ }
+ }
+
+ if (cc->open) {
+ cc->open(chr, backend, be_opened, errp);
+ }
}
-static Chardev *qemu_chr_open_null(const CharDriver *driver,
- const char *id,
- ChardevBackend *backend,
- ChardevReturn *ret,
- bool *be_opened,
- Error **errp)
+static void char_init(Object *obj)
{
- Chardev *chr;
- ChardevCommon *common = backend->u.null.data;
+ Chardev *chr = CHARDEV(obj);
- chr = qemu_chr_alloc(driver, common, errp);
- if (!chr) {
- return NULL;
+ chr->logfd = -1;
+ qemu_mutex_init(&chr->chr_write_lock);
+}
+
+static void char_finalize(Object *obj)
+{
+ Chardev *chr = CHARDEV(obj);
+
+ if (chr->be) {
+ chr->be->chr = NULL;
+ }
+ g_free(chr->filename);
+ g_free(chr->label);
+ if (chr->logfd != -1) {
+ close(chr->logfd);
}
+ qemu_mutex_destroy(&chr->chr_write_lock);
+}
+
+static const TypeInfo char_type_info = {
+ .name = TYPE_CHARDEV,
+ .parent = TYPE_OBJECT,
+ .instance_size = sizeof(Chardev),
+ .instance_init = char_init,
+ .instance_finalize = char_finalize,
+ .abstract = true,
+ .class_size = sizeof(ChardevClass),
+};
+
+static int null_chr_write(Chardev *chr, const uint8_t *buf, int len)
+{
+ return len;
+}
+
+static void null_chr_open(Chardev *chr,
+ ChardevBackend *backend,
+ bool *be_opened,
+ Error **errp)
+{
*be_opened = false;
- return chr;
}
static const CharDriver null_driver = {
- .instance_size = sizeof(Chardev),
.kind = CHARDEV_BACKEND_KIND_NULL,
- .create = qemu_chr_open_null,
- .chr_write = null_chr_write,
+};
+
+static void char_null_class_init(ObjectClass *oc, void *data)
+{
+ ChardevClass *cc = CHARDEV_CLASS(oc);
+
+ cc->open = null_chr_open;
+ cc->chr_write = null_chr_write;
+}
+
+static const TypeInfo char_null_type_info = {
+ .name = TYPE_CHARDEV_NULL,
+ .parent = TYPE_CHARDEV,
+ .instance_size = sizeof(Chardev),
+ .class_init = char_null_class_init,
};
/* MUX driver for serial I/O splitting */
@@ -570,10 +604,12 @@ struct MuxChardev {
int64_t timestamps_start;
};
+#define MUX_CHARDEV(obj) OBJECT_CHECK(MuxChardev, (obj), TYPE_CHARDEV_MUX)
+
/* Called with chr_write_lock held. */
static int mux_chr_write(Chardev *chr, const uint8_t *buf, int len)
{
- MuxChardev *d = (MuxChardev *)chr;
+ MuxChardev *d = MUX_CHARDEV(chr);
int ret;
if (!d->timestamps) {
ret = qemu_chr_fe_write(&d->chr, buf, len);
@@ -707,7 +743,7 @@ static int mux_proc_byte(Chardev *chr, MuxChardev *d, int ch)
static void mux_chr_accept_input(Chardev *chr)
{
- MuxChardev *d = (MuxChardev *)chr;
+ MuxChardev *d = MUX_CHARDEV(chr);
int m = d->focus;
CharBackend *be = d->backends[m];
@@ -720,7 +756,7 @@ static void mux_chr_accept_input(Chardev *chr)
static int mux_chr_can_read(void *opaque)
{
- MuxChardev *d = opaque;
+ MuxChardev *d = MUX_CHARDEV(opaque);
int m = d->focus;
CharBackend *be = d->backends[m];
@@ -737,8 +773,8 @@ static int mux_chr_can_read(void *opaque)
static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
{
- Chardev *chr = opaque;
- MuxChardev *d = opaque;
+ Chardev *chr = CHARDEV(opaque);
+ MuxChardev *d = MUX_CHARDEV(opaque);
int m = d->focus;
CharBackend *be = d->backends[m];
int i;
@@ -760,7 +796,7 @@ static bool muxes_realized;
static void mux_chr_event(void *opaque, int event)
{
- MuxChardev *d = opaque;
+ MuxChardev *d = MUX_CHARDEV(opaque);
int i;
if (!muxes_realized) {
@@ -789,8 +825,8 @@ static void muxes_realize_done(Notifier *notifier, void *unused)
Chardev *chr;
QTAILQ_FOREACH(chr, &chardevs, next) {
- if (qemu_chr_get_kind(chr) == CHARDEV_BACKEND_KIND_MUX) {
- MuxChardev *d = (MuxChardev *)chr;
+ if (CHARDEV_IS_MUX(chr)) {
+ MuxChardev *d = MUX_CHARDEV(chr);
int i;
/* send OPENED to all already-attached FEs */
@@ -812,19 +848,20 @@ static Notifier muxes_realize_notify = {
static GSource *mux_chr_add_watch(Chardev *s, GIOCondition cond)
{
- MuxChardev *d = (MuxChardev *)s;
+ MuxChardev *d = MUX_CHARDEV(s);
Chardev *chr = qemu_chr_fe_get_driver(&d->chr);
+ ChardevClass *cc = CHARDEV_GET_CLASS(chr);
- if (!chr->driver->chr_add_watch) {
+ if (!cc->chr_add_watch) {
return NULL;
}
- return chr->driver->chr_add_watch(chr, cond);
+ return cc->chr_add_watch(chr, cond);
}
static void mux_chr_free(struct Chardev *chr)
{
- MuxChardev *d = (MuxChardev *)chr;
+ MuxChardev *d = MUX_CHARDEV(chr);
int i;
for (i = 0; i < d->mux_cnt; i++) {
@@ -838,7 +875,7 @@ static void mux_chr_free(struct Chardev *chr)
static void mux_chr_set_handlers(Chardev *chr, GMainContext *context)
{
- MuxChardev *d = (MuxChardev *)chr;
+ MuxChardev *d = MUX_CHARDEV(chr);
/* Fix up the real driver with mux routines */
qemu_chr_fe_set_handlers(&d->chr,
@@ -851,7 +888,7 @@ static void mux_chr_set_handlers(Chardev *chr, GMainContext *context)
static void mux_set_focus(Chardev *chr, int focus)
{
- MuxChardev *d = (MuxChardev *)chr;
+ MuxChardev *d = MUX_CHARDEV(chr);
assert(focus >= 0);
assert(focus < d->mux_cnt);
@@ -865,40 +902,27 @@ static void mux_set_focus(Chardev *chr, int focus)
mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
}
-static Chardev *qemu_chr_open_mux(const CharDriver *driver,
- const char *id,
- ChardevBackend *backend,
- ChardevReturn *ret,
- bool *be_opened,
- Error **errp)
+static void qemu_chr_open_mux(Chardev *chr,
+ ChardevBackend *backend,
+ bool *be_opened,
+ Error **errp)
{
ChardevMux *mux = backend->u.mux.data;
- Chardev *chr, *drv;
- MuxChardev *d;
- ChardevCommon *common = qapi_ChardevMux_base(mux);
+ Chardev *drv;
+ MuxChardev *d = MUX_CHARDEV(chr);
drv = qemu_chr_find(mux->chardev);
if (drv == NULL) {
error_setg(errp, "mux: base chardev %s not found", mux->chardev);
- return NULL;
+ return;
}
- chr = qemu_chr_alloc(driver, common, errp);
- if (!chr) {
- return NULL;
- }
- d = (MuxChardev *)chr;
d->focus = -1;
/* only default to opened state if we've realized the initial
* set of muxes
*/
*be_opened = muxes_realized;
- if (!qemu_chr_fe_init(&d->chr, drv, errp)) {
- qemu_chr_free(chr);
- return NULL;
- }
-
- return chr;
+ qemu_chr_fe_init(&d->chr, drv, errp);
}
Chardev *qemu_chr_fe_get_driver(CharBackend *be)
@@ -910,8 +934,8 @@ bool qemu_chr_fe_init(CharBackend *b, Chardev *s, Error **errp)
{
int tag = 0;
- if (qemu_chr_get_kind(s) == CHARDEV_BACKEND_KIND_MUX) {
- MuxChardev *d = (MuxChardev *)s;
+ if (CHARDEV_IS_MUX(s)) {
+ MuxChardev *d = MUX_CHARDEV(s);
if (d->mux_cnt >= MAX_MUX) {
goto unavailable;
@@ -937,8 +961,8 @@ unavailable:
static bool qemu_chr_is_busy(Chardev *s)
{
- if (qemu_chr_get_kind(s) == CHARDEV_BACKEND_KIND_MUX) {
- MuxChardev *d = (MuxChardev *)s;
+ if (CHARDEV_IS_MUX(s)) {
+ MuxChardev *d = MUX_CHARDEV(s);
return d->mux_cnt >= 0;
} else {
return s->be != NULL;
@@ -954,8 +978,8 @@ void qemu_chr_fe_deinit(CharBackend *b)
if (b->chr->be == b) {
b->chr->be = NULL;
}
- if (qemu_chr_get_kind(b->chr) == CHARDEV_BACKEND_KIND_MUX) {
- MuxChardev *d = (MuxChardev *)b->chr;
+ if (CHARDEV_IS_MUX(b->chr)) {
+ MuxChardev *d = MUX_CHARDEV(b->chr);
d->backends[b->tag] = NULL;
}
b->chr = NULL;
@@ -971,6 +995,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
bool set_open)
{
Chardev *s;
+ ChardevClass *cc;
int fe_open;
s = b->chr;
@@ -978,6 +1003,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
return;
}
+ cc = CHARDEV_GET_CLASS(s);
if (!opaque && !fd_can_read && !fd_read && !fd_event) {
fe_open = 0;
remove_fd_in_watch(s);
@@ -988,8 +1014,8 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
b->chr_read = fd_read;
b->chr_event = fd_event;
b->opaque = opaque;
- if (s->driver->chr_update_read_handler) {
- s->driver->chr_update_read_handler(s, context);
+ if (cc->chr_update_read_handler) {
+ cc->chr_update_read_handler(s, context);
}
if (set_open) {
@@ -1005,7 +1031,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
}
}
- if (qemu_chr_get_kind(s) == CHARDEV_BACKEND_KIND_MUX) {
+ if (CHARDEV_IS_MUX(s)) {
mux_chr_set_handlers(s, context);
}
}
@@ -1016,7 +1042,7 @@ void qemu_chr_fe_take_focus(CharBackend *b)
return;
}
- if (qemu_chr_get_kind(b->chr) == CHARDEV_BACKEND_KIND_MUX) {
+ if (CHARDEV_IS_MUX(b->chr)) {
mux_set_focus(b->chr, b->tag);
}
}
@@ -1193,7 +1219,6 @@ static int io_channel_send(QIOChannel *ioc, const void *buf, size_t len)
return io_channel_send_full(ioc, buf, len, NULL, 0);
}
-
typedef struct FDChardev {
Chardev parent;
Chardev *chr;
@@ -1201,18 +1226,21 @@ typedef struct FDChardev {
int max_size;
} FDChardev;
+#define TYPE_CHARDEV_FD "chardev-fd"
+#define FD_CHARDEV(obj) OBJECT_CHECK(FDChardev, (obj), TYPE_CHARDEV_FD)
+
/* Called with chr_write_lock held. */
static int fd_chr_write(Chardev *chr, const uint8_t *buf, int len)
{
- FDChardev *s = (FDChardev *)chr;
+ FDChardev *s = FD_CHARDEV(chr);
return io_channel_send(s->ioc_out, buf, len);
}
static gboolean fd_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
{
- Chardev *chr = opaque;
- FDChardev *s = opaque;
+ Chardev *chr = CHARDEV(opaque);
+ FDChardev *s = FD_CHARDEV(opaque);
int len;
uint8_t buf[READ_BUF_LEN];
ssize_t ret;
@@ -1241,8 +1269,8 @@ static gboolean fd_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
static int fd_chr_read_poll(void *opaque)
{
- Chardev *chr = opaque;
- FDChardev *s = opaque;
+ Chardev *chr = CHARDEV(opaque);
+ FDChardev *s = FD_CHARDEV(opaque);
s->max_size = qemu_chr_be_can_write(chr);
return s->max_size;
@@ -1250,14 +1278,14 @@ static int fd_chr_read_poll(void *opaque)
static GSource *fd_chr_add_watch(Chardev *chr, GIOCondition cond)
{
- FDChardev *s = (FDChardev *)chr;
+ FDChardev *s = FD_CHARDEV(chr);
return qio_channel_create_watch(s->ioc_out, cond);
}
static void fd_chr_update_read_handler(Chardev *chr,
GMainContext *context)
{
- FDChardev *s = (FDChardev *)chr;
+ FDChardev *s = FD_CHARDEV(chr);
remove_fd_in_watch(chr);
if (s->ioc_in) {
@@ -1270,7 +1298,7 @@ static void fd_chr_update_read_handler(Chardev *chr,
static void fd_chr_free(struct Chardev *chr)
{
- FDChardev *s = (FDChardev *)chr;
+ FDChardev *s = FD_CHARDEV(chr);
remove_fd_in_watch(chr);
if (s->ioc_in) {
@@ -1284,19 +1312,12 @@ static void fd_chr_free(struct Chardev *chr)
}
/* open a character device to a unix fd */
-static Chardev *qemu_chr_open_fd(const CharDriver *driver,
- int fd_in, int fd_out,
- ChardevCommon *backend, Error **errp)
+static void qemu_chr_open_fd(Chardev *chr,
+ int fd_in, int fd_out)
{
- Chardev *chr;
- FDChardev *s;
+ FDChardev *s = FD_CHARDEV(chr);
char *name;
- chr = qemu_chr_alloc(driver, backend, errp);
- if (!chr) {
- return NULL;
- }
- s = (FDChardev *)chr;
s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in));
name = g_strdup_printf("chardev-file-in-%s", chr->label);
qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name);
@@ -1307,24 +1328,36 @@ static Chardev *qemu_chr_open_fd(const CharDriver *driver,
g_free(name);
qemu_set_nonblock(fd_out);
s->chr = chr;
+}
- return chr;
+static void char_fd_class_init(ObjectClass *oc, void *data)
+{
+ ChardevClass *cc = CHARDEV_CLASS(oc);
+
+ cc->chr_add_watch = fd_chr_add_watch;
+ cc->chr_write = fd_chr_write;
+ cc->chr_update_read_handler = fd_chr_update_read_handler;
+ cc->chr_free = fd_chr_free;
}
-static Chardev *qemu_chr_open_pipe(const CharDriver *driver,
- const char *id,
- ChardevBackend *backend,
- ChardevReturn *ret,
- bool *be_opened,
- Error **errp)
+static const TypeInfo char_fd_type_info = {
+ .name = TYPE_CHARDEV_FD,
+ .parent = TYPE_CHARDEV,
+ .instance_size = sizeof(FDChardev),
+ .class_init = char_fd_class_init,
+ .abstract = true,
+};
+
+static void qemu_chr_open_pipe(Chardev *chr,
+ ChardevBackend *backend,
+ bool *be_opened,
+ Error **errp)
{
ChardevHostdev *opts = backend->u.pipe.data;
int fd_in, fd_out;
char *filename_in;
char *filename_out;
const char *filename = opts->device;
- ChardevCommon *common = qapi_ChardevHostdev_base(opts);
-
filename_in = g_strdup_printf("%s.in", filename);
filename_out = g_strdup_printf("%s.out", filename);
@@ -1340,10 +1373,10 @@ static Chardev *qemu_chr_open_pipe(const CharDriver *driver,
TFR(fd_in = fd_out = qemu_open(filename, O_RDWR | O_BINARY));
if (fd_in < 0) {
error_setg_file_open(errp, errno, filename);
- return NULL;
+ return;
}
}
- return qemu_chr_open_fd(driver, fd_in, fd_out, common, errp);
+ qemu_chr_open_fd(chr, fd_in, fd_out);
}
/* init terminal so that we can grab keys */
@@ -1395,26 +1428,22 @@ static void qemu_chr_free_stdio(struct Chardev *chr)
fd_chr_free(chr);
}
-static Chardev *qemu_chr_open_stdio(const CharDriver *driver,
- const char *id,
- ChardevBackend *backend,
- ChardevReturn *ret,
- bool *be_opened,
- Error **errp)
+static void qemu_chr_open_stdio(Chardev *chr,
+ ChardevBackend *backend,
+ bool *be_opened,
+ Error **errp)
{
ChardevStdio *opts = backend->u.stdio.data;
- Chardev *chr;
struct sigaction act;
- ChardevCommon *common = qapi_ChardevStdio_base(opts);
if (is_daemonized()) {
error_setg(errp, "cannot use stdio with -daemonize");
- return NULL;
+ return;
}
if (stdio_in_use) {
error_setg(errp, "cannot use stdio by multiple character devices");
- return NULL;
+ return;
}
stdio_in_use = true;
@@ -1427,16 +1456,12 @@ static Chardev *qemu_chr_open_stdio(const CharDriver *driver,
act.sa_handler = term_stdio_handler;
sigaction(SIGCONT, &act, NULL);
- chr = qemu_chr_open_fd(driver, 0, 1, common, errp);
- if (!chr) {
- return NULL;
- }
+ qemu_chr_open_fd(chr, 0, 1);
+
if (opts->has_signal) {
stdio_allow_signal = opts->signal;
}
qemu_chr_set_echo_stdio(chr, false);
-
- return chr;
}
#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
@@ -1457,13 +1482,15 @@ typedef struct {
guint open_tag;
} PtyChardev;
+#define PTY_CHARDEV(obj) OBJECT_CHECK(PtyChardev, (obj), TYPE_CHARDEV_PTY)
+
static void pty_chr_update_read_handler_locked(Chardev *chr);
static void pty_chr_state(Chardev *chr, int connected);
static gboolean pty_chr_timer(gpointer opaque)
{
- struct Chardev *chr = opaque;
- PtyChardev *s = opaque;
+ struct Chardev *chr = CHARDEV(opaque);
+ PtyChardev *s = PTY_CHARDEV(opaque);
qemu_mutex_lock(&chr->chr_write_lock);
s->timer_tag = 0;
@@ -1479,7 +1506,7 @@ static gboolean pty_chr_timer(gpointer opaque)
/* Called with chr_write_lock held. */
static void pty_chr_rearm_timer(Chardev *chr, int ms)
{
- PtyChardev *s = (PtyChardev *)chr;
+ PtyChardev *s = PTY_CHARDEV(chr);
char *name;
if (s->timer_tag) {
@@ -1501,7 +1528,7 @@ static void pty_chr_rearm_timer(Chardev *chr, int ms)
/* Called with chr_write_lock held. */
static void pty_chr_update_read_handler_locked(Chardev *chr)
{
- PtyChardev *s = (PtyChardev *)chr;
+ PtyChardev *s = PTY_CHARDEV(chr);
GPollFD pfd;
int rc;
QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc);
@@ -1530,9 +1557,9 @@ static void pty_chr_update_read_handler(Chardev *chr,
}
/* Called with chr_write_lock held. */
-static int pty_chr_write(Chardev *chr, const uint8_t *buf, int len)
+static int char_pty_chr_write(Chardev *chr, const uint8_t *buf, int len)
{
- PtyChardev *s = (PtyChardev *)chr;
+ PtyChardev *s = PTY_CHARDEV(chr);
if (!s->connected) {
/* guest sends data, check for (re-)connect */
@@ -1546,7 +1573,7 @@ static int pty_chr_write(Chardev *chr, const uint8_t *buf, int len)
static GSource *pty_chr_add_watch(Chardev *chr, GIOCondition cond)
{
- PtyChardev *s = (PtyChardev *)chr;
+ PtyChardev *s = PTY_CHARDEV(chr);
if (!s->connected) {
return NULL;
}
@@ -1555,8 +1582,8 @@ static GSource *pty_chr_add_watch(Chardev *chr, GIOCondition cond)
static int pty_chr_read_poll(void *opaque)
{
- Chardev *chr = opaque;
- PtyChardev *s = opaque;
+ Chardev *chr = CHARDEV(opaque);
+ PtyChardev *s = PTY_CHARDEV(opaque);
s->read_bytes = qemu_chr_be_can_write(chr);
return s->read_bytes;
@@ -1564,8 +1591,8 @@ static int pty_chr_read_poll(void *opaque)
static gboolean pty_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
{
- Chardev *chr = opaque;
- PtyChardev *s = opaque;
+ Chardev *chr = CHARDEV(opaque);
+ PtyChardev *s = PTY_CHARDEV(opaque);
gsize len;
uint8_t buf[READ_BUF_LEN];
ssize_t ret;
@@ -1589,8 +1616,8 @@ static gboolean pty_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
static gboolean qemu_chr_be_generic_open_func(gpointer opaque)
{
- Chardev *chr = opaque;
- PtyChardev *s = opaque;
+ Chardev *chr = CHARDEV(opaque);
+ PtyChardev *s = PTY_CHARDEV(opaque);
s->open_tag = 0;
qemu_chr_be_generic_open(chr);
@@ -1600,7 +1627,7 @@ static gboolean qemu_chr_be_generic_open_func(gpointer opaque)
/* Called with chr_write_lock held. */
static void pty_chr_state(Chardev *chr, int connected)
{
- PtyChardev *s = (PtyChardev *)chr;
+ PtyChardev *s = PTY_CHARDEV(chr);
if (!connected) {
if (s->open_tag) {
@@ -1634,7 +1661,7 @@ static void pty_chr_state(Chardev *chr, int connected)
static void pty_chr_free(struct Chardev *chr)
{
- PtyChardev *s = (PtyChardev *)chr;
+ PtyChardev *s = PTY_CHARDEV(chr);
qemu_mutex_lock(&chr->chr_write_lock);
pty_chr_state(chr, 0);
@@ -1647,61 +1674,58 @@ static void pty_chr_free(struct Chardev *chr)
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
}
-static Chardev *qemu_chr_open_pty(const CharDriver *driver,
- const char *id,
- ChardevBackend *backend,
- ChardevReturn *ret,
- bool *be_opened,
- Error **errp)
+static void char_pty_open(Chardev *chr,
+ ChardevBackend *backend,
+ bool *be_opened,
+ Error **errp)
{
- Chardev *chr;
PtyChardev *s;
int master_fd, slave_fd;
char pty_name[PATH_MAX];
- ChardevCommon *common = backend->u.pty.data;
char *name;
master_fd = qemu_openpty_raw(&slave_fd, pty_name);
if (master_fd < 0) {
error_setg_errno(errp, errno, "Failed to create PTY");
- return NULL;
+ return;
}
close(slave_fd);
qemu_set_nonblock(master_fd);
- chr = qemu_chr_alloc(driver, common, errp);
- if (!chr) {
- close(master_fd);
- return NULL;
- }
-
chr->filename = g_strdup_printf("pty:%s", pty_name);
- ret->pty = g_strdup(pty_name);
- ret->has_pty = true;
-
error_report("char device redirected to %s (label %s)",
- pty_name, id);
+ pty_name, chr->label);
- s = (PtyChardev *)chr;
+ s = PTY_CHARDEV(chr);
s->ioc = QIO_CHANNEL(qio_channel_file_new_fd(master_fd));
name = g_strdup_printf("chardev-pty-%s", chr->label);
qio_channel_set_name(QIO_CHANNEL(s->ioc), name);
g_free(name);
s->timer_tag = 0;
*be_opened = false;
-
- return chr;
}
static const CharDriver pty_driver = {
- .instance_size = sizeof(PtyChardev),
.kind = CHARDEV_BACKEND_KIND_PTY,
- .create = qemu_chr_open_pty,
- .chr_write = pty_chr_write,
- .chr_update_read_handler = pty_chr_update_read_handler,
- .chr_add_watch = pty_chr_add_watch,
- .chr_free = pty_chr_free,
+};
+
+static void char_pty_class_init(ObjectClass *oc, void *data)
+{
+ ChardevClass *cc = CHARDEV_CLASS(oc);
+
+ cc->open = char_pty_open;
+ cc->chr_write = char_pty_chr_write;
+ cc->chr_update_read_handler = pty_chr_update_read_handler;
+ cc->chr_add_watch = pty_chr_add_watch;
+ cc->chr_free = pty_chr_free;
+}
+
+static const TypeInfo char_pty_type_info = {
+ .name = TYPE_CHARDEV_PTY,
+ .parent = TYPE_CHARDEV,
+ .instance_size = sizeof(PtyChardev),
+ .class_init = char_pty_class_init,
};
static void tty_serial_init(int fd, int speed,
@@ -1821,7 +1845,7 @@ static void tty_serial_init(int fd, int speed,
static int tty_serial_ioctl(Chardev *chr, int cmd, void *arg)
{
- FDChardev *s = (FDChardev *)chr;
+ FDChardev *s = FD_CHARDEV(chr);
QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc_in);
switch(cmd) {
@@ -1905,6 +1929,9 @@ typedef struct {
int mode;
} ParallelChardev;
+#define PARALLEL_CHARDEV(obj) \
+ OBJECT_CHECK(ParallelChardev, (obj), TYPE_CHARDEV_PARALLEL)
+
static int pp_hw_mode(ParallelChardev *s, uint16_t mode)
{
if (s->mode != mode) {
@@ -1918,7 +1945,7 @@ static int pp_hw_mode(ParallelChardev *s, uint16_t mode)
static int pp_ioctl(Chardev *chr, int cmd, void *arg)
{
- ParallelChardev *drv = (ParallelChardev *)chr;
+ ParallelChardev *drv = PARALLEL_CHARDEV(chr);
int fd = drv->fd;
uint8_t b;
@@ -1999,7 +2026,7 @@ static int pp_ioctl(Chardev *chr, int cmd, void *arg)
static void pp_free(Chardev *chr)
{
- ParallelChardev *drv = (ParallelChardev *)chr;
+ ParallelChardev *drv = PARALLEL_CHARDEV(chr);
int fd = drv->fd;
pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
@@ -2008,31 +2035,21 @@ static void pp_free(Chardev *chr)
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
}
-static Chardev *qemu_chr_open_pp_fd(const CharDriver *driver,
- int fd,
- ChardevCommon *backend,
- bool *be_opened,
- Error **errp)
+static void qemu_chr_open_pp_fd(Chardev *chr,
+ int fd,
+ bool *be_opened,
+ Error **errp)
{
- Chardev *chr;
- ParallelChardev *drv;
+ ParallelChardev *drv = PARALLEL_CHARDEV(chr);
if (ioctl(fd, PPCLAIM) < 0) {
error_setg_errno(errp, errno, "not a parallel port");
close(fd);
- return NULL;
- }
-
- chr = qemu_chr_alloc(driver, backend, errp);
- if (!chr) {
- return NULL;
+ return;
}
- drv = (ParallelChardev *)chr;
drv->fd = fd;
drv->mode = IEEE1284_MODE_COMPAT;
-
- return chr;
}
#endif /* __linux__ */
@@ -2045,9 +2062,12 @@ typedef struct {
int fd;
} ParallelChardev;
+#define PARALLEL_CHARDEV(obj) \
+ OBJECT_CHECK(ParallelChardev, (obj), TYPE_CHARDEV_PARALLEL)
+
static int pp_ioctl(Chardev *chr, int cmd, void *arg)
{
- ParallelChardev *drv = (ParallelChardev *)chr;
+ ParallelChardev *drv = PARALLEL_CHARDEV(chr);
uint8_t b;
switch (cmd) {
@@ -2087,23 +2107,14 @@ static int pp_ioctl(Chardev *chr, int cmd, void *arg)
return 0;
}
-static Chardev *qemu_chr_open_pp_fd(const CharDriver *driver,
- int fd,
- ChardevCommon *backend,
- bool *be_opened,
- Error **errp)
+static void qemu_chr_open_pp_fd(Chardev *chr,
+ int fd,
+ bool *be_opened,
+ Error **errp)
{
- Chardev *chr;
- ParallelChardev *drv;
-
- chr = qemu_chr_alloc(driver, backend, errp);
- if (!chr) {
- return NULL;
- }
- drv = (ParallelChardev *)chr;
+ ParallelChardev *drv = PARALLEL_CHARDEV(chr);
drv->fd = fd;
*be_opened = false;
- return chr;
}
#endif
@@ -2123,6 +2134,9 @@ typedef struct {
OVERLAPPED osend;
} WinChardev;
+#define TYPE_CHARDEV_WIN "chardev-win"
+#define WIN_CHARDEV(obj) OBJECT_CHECK(WinChardev, (obj), TYPE_CHARDEV_WIN)
+
typedef struct {
Chardev parent;
HANDLE hStdIn;
@@ -2132,6 +2146,10 @@ typedef struct {
uint8_t win_stdio_buf;
} WinStdioChardev;
+#define TYPE_CHARDEV_WIN_STDIO "chardev-win-stdio"
+#define WIN_STDIO_CHARDEV(obj) \
+ OBJECT_CHECK(WinStdioChardev, (obj), TYPE_CHARDEV_WIN_STDIO)
+
#define NSENDBUF 2048
#define NRECVBUF 2048
#define MAXCONNECT 1
@@ -2142,7 +2160,7 @@ static int win_chr_pipe_poll(void *opaque);
static void win_chr_free(Chardev *chr)
{
- WinChardev *s = (WinChardev *)chr;
+ WinChardev *s = WIN_CHARDEV(chr);
if (s->hsend) {
CloseHandle(s->hsend);
@@ -2166,7 +2184,7 @@ static void win_chr_free(Chardev *chr)
static int win_chr_init(Chardev *chr, const char *filename, Error **errp)
{
- WinChardev *s = (WinChardev *)chr;
+ WinChardev *s = WIN_CHARDEV(chr);
COMMCONFIG comcfg;
COMMTIMEOUTS cto = { 0, 0, 0, 0, 0};
COMSTAT comstat;
@@ -2234,7 +2252,7 @@ static int win_chr_init(Chardev *chr, const char *filename, Error **errp)
/* Called with chr_write_lock held. */
static int win_chr_write(Chardev *chr, const uint8_t *buf, int len1)
{
- WinChardev *s = (WinChardev *)chr;
+ WinChardev *s = WIN_CHARDEV(chr);
DWORD len, ret, size, err;
len = len1;
@@ -2268,7 +2286,7 @@ static int win_chr_write(Chardev *chr, const uint8_t *buf, int len1)
static int win_chr_read_poll(Chardev *chr)
{
- WinChardev *s = (WinChardev *)chr;
+ WinChardev *s = WIN_CHARDEV(chr);
s->max_size = qemu_chr_be_can_write(chr);
return s->max_size;
@@ -2276,7 +2294,8 @@ static int win_chr_read_poll(Chardev *chr)
static void win_chr_readfile(Chardev *chr)
{
- WinChardev *s = (WinChardev *)chr;
+ WinChardev *s = WIN_CHARDEV(chr);
+
int ret, err;
uint8_t buf[READ_BUF_LEN];
DWORD size;
@@ -2298,7 +2317,7 @@ static void win_chr_readfile(Chardev *chr)
static void win_chr_read(Chardev *chr)
{
- WinChardev *s = (WinChardev *)chr;
+ WinChardev *s = WIN_CHARDEV(chr);
if (s->len > s->max_size)
s->len = s->max_size;
@@ -2310,8 +2329,8 @@ static void win_chr_read(Chardev *chr)
static int win_chr_poll(void *opaque)
{
- Chardev *chr = opaque;
- WinChardev *s = opaque;
+ Chardev *chr = CHARDEV(opaque);
+ WinChardev *s = WIN_CHARDEV(opaque);
COMSTAT status;
DWORD comerr;
@@ -2327,8 +2346,8 @@ static int win_chr_poll(void *opaque)
static int win_chr_pipe_poll(void *opaque)
{
- Chardev *chr = opaque;
- WinChardev *s = opaque;
+ Chardev *chr = CHARDEV(opaque);
+ WinChardev *s = WIN_CHARDEV(opaque);
DWORD size;
PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL);
@@ -2344,7 +2363,7 @@ static int win_chr_pipe_poll(void *opaque)
static int win_chr_pipe_init(Chardev *chr, const char *filename,
Error **errp)
{
- WinChardev *s = (WinChardev *)chr;
+ WinChardev *s = WIN_CHARDEV(chr);
OVERLAPPED ov;
int ret;
DWORD size;
@@ -2406,65 +2425,66 @@ static int win_chr_pipe_init(Chardev *chr, const char *filename,
}
-static Chardev *qemu_chr_open_pipe(const CharDriver *driver,
- const char *id,
- ChardevBackend *backend,
- ChardevReturn *ret,
- bool *be_opened,
- Error **errp)
+static void qemu_chr_open_pipe(Chardev *chr,
+ ChardevBackend *backend,
+ bool *be_opened,
+ Error **errp)
{
ChardevHostdev *opts = backend->u.pipe.data;
const char *filename = opts->device;
- Chardev *chr;
- ChardevCommon *common = qapi_ChardevHostdev_base(opts);
-
- chr = qemu_chr_alloc(driver, common, errp);
- if (!chr) {
- return NULL;
- }
if (win_chr_pipe_init(chr, filename, errp) < 0) {
- qemu_chr_free_common(chr);
- return NULL;
+ return;
}
- return chr;
}
-static Chardev *qemu_chr_open_win_file(const CharDriver *driver,
- HANDLE fd_out,
- ChardevCommon *backend,
- Error **errp)
+static void qemu_chr_open_win_file(Chardev *chr, HANDLE fd_out)
{
- Chardev *chr;
- WinChardev *s;
+ WinChardev *s = WIN_CHARDEV(chr);
- chr = qemu_chr_alloc(driver, backend, errp);
- if (!chr) {
- return NULL;
- }
- s = (WinChardev *)chr;
s->hcom = fd_out;
- return chr;
}
-static Chardev *qemu_chr_open_win_con(const CharDriver *driver,
- const char *id,
- ChardevBackend *backend,
- ChardevReturn *ret,
- bool *be_opened,
- Error **errp)
+static void char_win_class_init(ObjectClass *oc, void *data)
{
- ChardevCommon *common = backend->u.console.data;
- return qemu_chr_open_win_file(driver,
- GetStdHandle(STD_OUTPUT_HANDLE),
- common, errp);
+ ChardevClass *cc = CHARDEV_CLASS(oc);
+
+ cc->chr_write = win_chr_write;
+ cc->chr_free = win_chr_free;
}
-static const CharDriver console_driver = {
+static const TypeInfo char_win_type_info = {
+ .name = TYPE_CHARDEV_WIN,
+ .parent = TYPE_CHARDEV,
.instance_size = sizeof(WinChardev),
+ .class_init = char_win_class_init,
+ .abstract = true,
+};
+
+static void qemu_chr_open_win_con(Chardev *chr,
+ ChardevBackend *backend,
+ bool *be_opened,
+ Error **errp)
+{
+ qemu_chr_open_win_file(chr, GetStdHandle(STD_OUTPUT_HANDLE));
+}
+
+static const CharDriver console_driver = {
.kind = CHARDEV_BACKEND_KIND_CONSOLE,
- .create = qemu_chr_open_win_con,
- .chr_write = win_chr_write,
+};
+
+static void char_console_class_init(ObjectClass *oc, void *data)
+{
+ ChardevClass *cc = CHARDEV_CLASS(oc);
+
+ cc->open = qemu_chr_open_win_con;
+ cc->chr_free = NULL;
+}
+
+static const TypeInfo char_console_type_info = {
+ .name = TYPE_CHARDEV_CONSOLE,
+ .parent = TYPE_CHARDEV_WIN,
+ .class_init = char_console_class_init,
};
static int win_stdio_write(Chardev *chr, const uint8_t *buf, int len)
@@ -2488,8 +2508,8 @@ static int win_stdio_write(Chardev *chr, const uint8_t *buf, int len)
static void win_stdio_wait_func(void *opaque)
{
- Chardev *chr = opaque;
- WinStdioChardev *stdio = opaque;
+ Chardev *chr = CHARDEV(opaque);
+ WinStdioChardev *stdio = WIN_STDIO_CHARDEV(opaque);
INPUT_RECORD buf[4];
int ret;
DWORD dwSize;
@@ -2522,7 +2542,7 @@ static void win_stdio_wait_func(void *opaque)
static DWORD WINAPI win_stdio_thread(LPVOID param)
{
- WinStdioChardev *stdio = param;
+ WinStdioChardev *stdio = WIN_STDIO_CHARDEV(param);
int ret;
DWORD dwSize;
@@ -2560,8 +2580,8 @@ static DWORD WINAPI win_stdio_thread(LPVOID param)
static void win_stdio_thread_wait_func(void *opaque)
{
- Chardev *chr = opaque;
- WinStdioChardev *stdio = opaque;
+ Chardev *chr = CHARDEV(opaque);
+ WinStdioChardev *stdio = WIN_STDIO_CHARDEV(opaque);
if (qemu_chr_be_can_write(chr)) {
qemu_chr_be_write(chr, &stdio->win_stdio_buf, 1);
@@ -2572,7 +2592,7 @@ static void win_stdio_thread_wait_func(void *opaque)
static void qemu_chr_set_echo_win_stdio(Chardev *chr, bool echo)
{
- WinStdioChardev *stdio = (WinStdioChardev *)chr;
+ WinStdioChardev *stdio = WIN_STDIO_CHARDEV(chr);
DWORD dwMode = 0;
GetConsoleMode(stdio->hStdIn, &dwMode);
@@ -2586,7 +2606,7 @@ static void qemu_chr_set_echo_win_stdio(Chardev *chr, bool echo)
static void win_stdio_free(Chardev *chr)
{
- WinStdioChardev *stdio = (WinStdioChardev *)chr;
+ WinStdioChardev *stdio = WIN_STDIO_CHARDEV(chr);
if (stdio->hInputReadyEvent != INVALID_HANDLE_VALUE) {
CloseHandle(stdio->hInputReadyEvent);
@@ -2599,29 +2619,26 @@ static void win_stdio_free(Chardev *chr)
}
}
-static Chardev *qemu_chr_open_stdio(const CharDriver *driver,
- const char *id,
- ChardevBackend *backend,
- ChardevReturn *ret,
- bool *be_opened,
- Error **errp)
+static const TypeInfo char_win_stdio_type_info = {
+ .name = TYPE_CHARDEV_WIN_STDIO,
+ .parent = TYPE_CHARDEV,
+ .instance_size = sizeof(WinStdioChardev),
+ .abstract = true,
+};
+
+static void qemu_chr_open_stdio(Chardev *chr,
+ ChardevBackend *backend,
+ bool *be_opened,
+ Error **errp)
{
- Chardev *chr;
- WinStdioChardev *stdio;
+ WinStdioChardev *stdio = WIN_STDIO_CHARDEV(chr);
DWORD dwMode;
int is_console = 0;
- ChardevCommon *common = qapi_ChardevStdio_base(backend->u.stdio.data);
-
- chr = qemu_chr_alloc(driver, common, errp);
- if (!chr) {
- return NULL;
- }
- stdio = (WinStdioChardev *)chr;
stdio->hStdIn = GetStdHandle(STD_INPUT_HANDLE);
if (stdio->hStdIn == INVALID_HANDLE_VALUE) {
error_setg(errp, "cannot open stdio: invalid handle");
- return NULL;
+ return;
}
is_console = GetConsoleMode(stdio->hStdIn, &dwMode) != 0;
@@ -2668,7 +2685,7 @@ static Chardev *qemu_chr_open_stdio(const CharDriver *driver,
qemu_chr_set_echo_win_stdio(chr, false);
- return chr;
+ return;
err3:
qemu_del_wait_object(stdio->hInputReadyEvent, NULL, NULL);
@@ -2677,7 +2694,6 @@ err2:
CloseHandle(stdio->hInputDoneEvent);
err1:
qemu_del_wait_object(stdio->hStdIn, NULL, NULL);
- return NULL;
}
#endif /* !_WIN32 */
@@ -2693,10 +2709,12 @@ typedef struct {
int max_size;
} UdpChardev;
+#define UDP_CHARDEV(obj) OBJECT_CHECK(UdpChardev, (obj), TYPE_CHARDEV_UDP)
+
/* Called with chr_write_lock held. */
static int udp_chr_write(Chardev *chr, const uint8_t *buf, int len)
{
- UdpChardev *s = (UdpChardev *)chr;
+ UdpChardev *s = UDP_CHARDEV(chr);
return qio_channel_write(
s->ioc, (const char *)buf, len, NULL);
@@ -2704,8 +2722,8 @@ static int udp_chr_write(Chardev *chr, const uint8_t *buf, int len)
static int udp_chr_read_poll(void *opaque)
{
- Chardev *chr = opaque;
- UdpChardev *s = opaque;
+ Chardev *chr = CHARDEV(opaque);
+ UdpChardev *s = UDP_CHARDEV(opaque);
s->max_size = qemu_chr_be_can_write(chr);
@@ -2722,8 +2740,8 @@ static int udp_chr_read_poll(void *opaque)
static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
{
- Chardev *chr = opaque;
- UdpChardev *s = opaque;
+ Chardev *chr = CHARDEV(opaque);
+ UdpChardev *s = UDP_CHARDEV(opaque);
ssize_t ret;
if (s->max_size == 0) {
@@ -2750,7 +2768,7 @@ static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
static void udp_chr_update_read_handler(Chardev *chr,
GMainContext *context)
{
- UdpChardev *s = (UdpChardev *)chr;
+ UdpChardev *s = UDP_CHARDEV(chr);
remove_fd_in_watch(chr);
if (s->ioc) {
@@ -2763,7 +2781,7 @@ static void udp_chr_update_read_handler(Chardev *chr,
static void udp_chr_free(Chardev *chr)
{
- UdpChardev *s = (UdpChardev *)chr;
+ UdpChardev *s = UDP_CHARDEV(chr);
remove_fd_in_watch(chr);
if (s->ioc) {
@@ -2801,11 +2819,14 @@ typedef struct {
bool connect_err_reported;
} SocketChardev;
+#define SOCKET_CHARDEV(obj) \
+ OBJECT_CHECK(SocketChardev, (obj), TYPE_CHARDEV_SOCKET)
+
static gboolean socket_reconnect_timeout(gpointer opaque);
static void qemu_chr_socket_restart_timer(Chardev *chr)
{
- SocketChardev *s = (SocketChardev *)chr;
+ SocketChardev *s = SOCKET_CHARDEV(chr);
char *name;
assert(s->connected == 0);
@@ -2819,7 +2840,7 @@ static void qemu_chr_socket_restart_timer(Chardev *chr)
static void check_report_connect_error(Chardev *chr,
Error *err)
{
- SocketChardev *s = (SocketChardev *)chr;
+ SocketChardev *s = SOCKET_CHARDEV(chr);
if (!s->connect_err_reported) {
error_report("Unable to connect character device %s: %s",
@@ -2836,7 +2857,7 @@ static gboolean tcp_chr_accept(QIOChannel *chan,
/* Called with chr_write_lock held. */
static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len)
{
- SocketChardev *s = (SocketChardev *)chr;
+ SocketChardev *s = SOCKET_CHARDEV(chr);
if (s->connected) {
int ret = io_channel_send_full(s->ioc, buf, len,
@@ -2859,8 +2880,8 @@ static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len)
static int tcp_chr_read_poll(void *opaque)
{
- Chardev *chr = opaque;
- SocketChardev *s = opaque;
+ Chardev *chr = CHARDEV(opaque);
+ SocketChardev *s = SOCKET_CHARDEV(opaque);
if (!s->connected)
return 0;
s->max_size = qemu_chr_be_can_write(chr);
@@ -2919,7 +2940,7 @@ static void tcp_chr_process_IAC_bytes(Chardev *chr,
static int tcp_get_msgfds(Chardev *chr, int *fds, int num)
{
- SocketChardev *s = (SocketChardev *)chr;
+ SocketChardev *s = SOCKET_CHARDEV(chr);
int to_copy = (s->read_msgfds_num < num) ? s->read_msgfds_num : num;
@@ -2945,7 +2966,7 @@ static int tcp_get_msgfds(Chardev *chr, int *fds, int num)
static int tcp_set_msgfds(Chardev *chr, int *fds, int num)
{
- SocketChardev *s = (SocketChardev *)chr;
+ SocketChardev *s = SOCKET_CHARDEV(chr);
/* clear old pending fd array */
g_free(s->write_msgfds);
@@ -2970,7 +2991,7 @@ static int tcp_set_msgfds(Chardev *chr, int *fds, int num)
static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
{
- SocketChardev *s = (SocketChardev *)chr;
+ SocketChardev *s = SOCKET_CHARDEV(chr);
struct iovec iov = { .iov_base = buf, .iov_len = len };
int ret;
size_t i;
@@ -3027,13 +3048,13 @@ static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
static GSource *tcp_chr_add_watch(Chardev *chr, GIOCondition cond)
{
- SocketChardev *s = (SocketChardev *)chr;
+ SocketChardev *s = SOCKET_CHARDEV(chr);
return qio_channel_create_watch(s->ioc, cond);
}
static void tcp_chr_free_connection(Chardev *chr)
{
- SocketChardev *s = (SocketChardev *)chr;
+ SocketChardev *s = SOCKET_CHARDEV(chr);
int i;
if (!s->connected) {
@@ -3062,7 +3083,7 @@ static void tcp_chr_free_connection(Chardev *chr)
static void tcp_chr_disconnect(Chardev *chr)
{
- SocketChardev *s = (SocketChardev *)chr;
+ SocketChardev *s = SOCKET_CHARDEV(chr);
if (!s->connected) {
return;
@@ -3084,8 +3105,8 @@ static void tcp_chr_disconnect(Chardev *chr)
static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
{
- Chardev *chr = opaque;
- SocketChardev *s = opaque;
+ Chardev *chr = CHARDEV(opaque);
+ SocketChardev *s = SOCKET_CHARDEV(opaque);
uint8_t buf[READ_BUF_LEN];
int len, size;
@@ -3111,7 +3132,7 @@ static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len)
{
- SocketChardev *s = (SocketChardev *)chr;
+ SocketChardev *s = SOCKET_CHARDEV(chr);
int size;
if (!s->connected) {
@@ -3129,8 +3150,8 @@ static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len)
static void tcp_chr_connect(void *opaque)
{
- Chardev *chr = opaque;
- SocketChardev *s = opaque;
+ Chardev *chr = CHARDEV(opaque);
+ SocketChardev *s = SOCKET_CHARDEV(opaque);
g_free(chr->filename);
chr->filename = sockaddr_to_str(
@@ -3151,7 +3172,7 @@ static void tcp_chr_connect(void *opaque)
static void tcp_chr_update_read_handler(Chardev *chr,
GMainContext *context)
{
- SocketChardev *s = (SocketChardev *)chr;
+ SocketChardev *s = SOCKET_CHARDEV(chr);
if (!s->connected) {
return;
@@ -3202,7 +3223,7 @@ static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
static void tcp_chr_telnet_init(Chardev *chr)
{
- SocketChardev *s = (SocketChardev *)chr;
+ SocketChardev *s = SOCKET_CHARDEV(chr);
TCPCharDriverTelnetInit *init =
g_new0(TCPCharDriverTelnetInit, 1);
size_t n = 0;
@@ -3253,7 +3274,7 @@ static void tcp_chr_tls_handshake(QIOTask *task,
static void tcp_chr_tls_init(Chardev *chr)
{
- SocketChardev *s = (SocketChardev *)chr;
+ SocketChardev *s = SOCKET_CHARDEV(chr);
QIOChannelTLS *tioc;
Error *err = NULL;
gchar *name;
@@ -3292,7 +3313,7 @@ static void tcp_chr_tls_init(Chardev *chr)
static void tcp_chr_set_client_ioc_name(Chardev *chr,
QIOChannelSocket *sioc)
{
- SocketChardev *s = (SocketChardev *)chr;
+ SocketChardev *s = SOCKET_CHARDEV(chr);
char *name;
name = g_strdup_printf("chardev-tcp-%s-%s",
s->is_listen ? "server" : "client",
@@ -3304,7 +3325,7 @@ static void tcp_chr_set_client_ioc_name(Chardev *chr,
static int tcp_chr_new_client(Chardev *chr, QIOChannelSocket *sioc)
{
- SocketChardev *s = (SocketChardev *)chr;
+ SocketChardev *s = SOCKET_CHARDEV(chr);
if (s->ioc != NULL) {
return -1;
@@ -3358,7 +3379,7 @@ static gboolean tcp_chr_accept(QIOChannel *channel,
GIOCondition cond,
void *opaque)
{
- Chardev *chr = opaque;
+ Chardev *chr = CHARDEV(opaque);
QIOChannelSocket *sioc;
sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(channel),
@@ -3376,7 +3397,7 @@ static gboolean tcp_chr_accept(QIOChannel *channel,
static int tcp_chr_wait_connected(Chardev *chr, Error **errp)
{
- SocketChardev *s = (SocketChardev *)chr;
+ SocketChardev *s = SOCKET_CHARDEV(chr);
QIOChannelSocket *sioc;
/* It can't wait on s->connected, since it is set asynchronously
@@ -3405,8 +3426,10 @@ static int tcp_chr_wait_connected(Chardev *chr, Error **errp)
static int qemu_chr_wait_connected(Chardev *chr, Error **errp)
{
- if (chr->driver->chr_wait_connected) {
- return chr->driver->chr_wait_connected(chr, errp);
+ ChardevClass *cc = CHARDEV_GET_CLASS(chr);
+
+ if (cc->chr_wait_connected) {
+ return cc->chr_wait_connected(chr, errp);
}
return 0;
@@ -3424,7 +3447,7 @@ int qemu_chr_fe_wait_connected(CharBackend *be, Error **errp)
static void tcp_chr_free(Chardev *chr)
{
- SocketChardev *s = (SocketChardev *)chr;
+ SocketChardev *s = SOCKET_CHARDEV(chr);
tcp_chr_free_connection(chr);
@@ -3451,8 +3474,8 @@ static void tcp_chr_free(Chardev *chr)
static void qemu_chr_socket_connected(QIOTask *task, void *opaque)
{
QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task));
- Chardev *chr = opaque;
- SocketChardev *s = (SocketChardev *)chr;
+ Chardev *chr = CHARDEV(opaque);
+ SocketChardev *s = SOCKET_CHARDEV(chr);
Error *err = NULL;
if (qio_task_propagate_error(task, &err)) {
@@ -3480,9 +3503,12 @@ typedef struct {
uint8_t *cbuf;
} RingBufChardev;
+#define RINGBUF_CHARDEV(obj) \
+ OBJECT_CHECK(RingBufChardev, (obj), TYPE_CHARDEV_RINGBUF)
+
static size_t ringbuf_count(const Chardev *chr)
{
- const RingBufChardev *d = (RingBufChardev *)chr;
+ const RingBufChardev *d = RINGBUF_CHARDEV(chr);
return d->prod - d->cons;
}
@@ -3490,7 +3516,7 @@ static size_t ringbuf_count(const Chardev *chr)
/* Called with chr_write_lock held. */
static int ringbuf_chr_write(Chardev *chr, const uint8_t *buf, int len)
{
- RingBufChardev *d = (RingBufChardev *)chr;
+ RingBufChardev *d = RINGBUF_CHARDEV(chr);
int i;
if (!buf || (len < 0)) {
@@ -3509,7 +3535,7 @@ static int ringbuf_chr_write(Chardev *chr, const uint8_t *buf, int len)
static int ringbuf_chr_read(Chardev *chr, uint8_t *buf, int len)
{
- RingBufChardev *d = (RingBufChardev *)chr;
+ RingBufChardev *d = RINGBUF_CHARDEV(chr);
int i;
qemu_mutex_lock(&chr->chr_write_lock);
@@ -3523,51 +3549,30 @@ static int ringbuf_chr_read(Chardev *chr, uint8_t *buf, int len)
static void ringbuf_chr_free(struct Chardev *chr)
{
- RingBufChardev *d = (RingBufChardev *)chr;
+ RingBufChardev *d = RINGBUF_CHARDEV(chr);
g_free(d->cbuf);
}
-static Chardev *qemu_chr_open_ringbuf(const CharDriver *driver,
- const char *id,
- ChardevBackend *backend,
- ChardevReturn *ret,
- bool *be_opened,
- Error **errp)
+static void qemu_chr_open_ringbuf(Chardev *chr,
+ ChardevBackend *backend,
+ bool *be_opened,
+ Error **errp)
{
ChardevRingbuf *opts = backend->u.ringbuf.data;
- ChardevCommon *common = qapi_ChardevRingbuf_base(opts);
- Chardev *chr;
- RingBufChardev *d;
-
- chr = qemu_chr_alloc(driver, common, errp);
- if (!chr) {
- return NULL;
- }
- d = (RingBufChardev *)chr;
+ RingBufChardev *d = RINGBUF_CHARDEV(chr);
d->size = opts->has_size ? opts->size : 65536;
/* The size must be power of 2 */
if (d->size & (d->size - 1)) {
error_setg(errp, "size of ringbuf chardev must be power of two");
- goto fail;
+ return;
}
d->prod = 0;
d->cons = 0;
d->cbuf = g_malloc0(d->size);
-
- return chr;
-
-fail:
- qemu_chr_free_common(chr);
- return NULL;
-}
-
-ChardevBackendKind qemu_chr_get_kind(const Chardev *chr)
-{
- return chr->driver->kind;
}
void qmp_ringbuf_write(const char *device, const char *data,
@@ -3585,7 +3590,7 @@ void qmp_ringbuf_write(const char *device, const char *data,
return;
}
- if (!qemu_chr_is_ringbuf(chr)) {
+ if (!CHARDEV_IS_RINGBUF(chr)) {
error_setg(errp,"%s is not a ringbuf device", device);
return;
}
@@ -3629,7 +3634,7 @@ char *qmp_ringbuf_read(const char *device, int64_t size,
return NULL;
}
- if (!qemu_chr_is_ringbuf(chr)) {
+ if (!CHARDEV_IS_RINGBUF(chr)) {
error_setg(errp,"%s is not a ringbuf device", device);
return NULL;
}
@@ -3849,20 +3854,31 @@ static void qemu_chr_parse_stdio(QemuOpts *opts, ChardevBackend *backend,
static const CharDriver stdio_driver = {
.kind = CHARDEV_BACKEND_KIND_STDIO,
.parse = qemu_chr_parse_stdio,
- .create = qemu_chr_open_stdio,
+};
+
+static void char_stdio_class_init(ObjectClass *oc, void *data)
+{
+ ChardevClass *cc = CHARDEV_CLASS(oc);
+
+ cc->open = qemu_chr_open_stdio;
#ifdef _WIN32
- sizeof(WinStdioChardev),
- .chr_write = win_stdio_write,
- .chr_set_echo = qemu_chr_set_echo_win_stdio,
- .chr_free = win_stdio_free,
+ cc->chr_write = win_stdio_write;
+ cc->chr_set_echo = qemu_chr_set_echo_win_stdio;
+ cc->chr_free = win_stdio_free;
#else
- sizeof(FDChardev),
- .chr_add_watch = fd_chr_add_watch,
- .chr_write = fd_chr_write,
- .chr_update_read_handler = fd_chr_update_read_handler,
- .chr_set_echo = qemu_chr_set_echo_stdio,
- .chr_free = qemu_chr_free_stdio,
+ cc->chr_set_echo = qemu_chr_set_echo_stdio;
+ cc->chr_free = qemu_chr_free_stdio;
#endif
+}
+
+static const TypeInfo char_stdio_type_info = {
+ .name = TYPE_CHARDEV_STDIO,
+#ifdef _WIN32
+ .parent = TYPE_CHARDEV_WIN_STDIO,
+#else
+ .parent = TYPE_CHARDEV_FD,
+#endif
+ .class_init = char_stdio_class_init,
};
#ifdef HAVE_CHARDEV_SERIAL
@@ -3917,18 +3933,23 @@ static void qemu_chr_parse_pipe(QemuOpts *opts, ChardevBackend *backend,
static const CharDriver pipe_driver = {
.kind = CHARDEV_BACKEND_KIND_PIPE,
.parse = qemu_chr_parse_pipe,
- .create = qemu_chr_open_pipe,
+};
+
+static void char_pipe_class_init(ObjectClass *oc, void *data)
+{
+ ChardevClass *cc = CHARDEV_CLASS(oc);
+
+ cc->open = qemu_chr_open_pipe;
+}
+
+static const TypeInfo char_pipe_type_info = {
+ .name = TYPE_CHARDEV_PIPE,
#ifdef _WIN32
- sizeof(WinChardev),
- .chr_write = win_chr_write,
- .chr_free = win_chr_free,
+ .parent = TYPE_CHARDEV_WIN,
#else
- sizeof(FDChardev),
- .chr_add_watch = fd_chr_add_watch,
- .chr_write = fd_chr_write,
- .chr_update_read_handler = fd_chr_update_read_handler,
- .chr_free = fd_chr_free,
+ .parent = TYPE_CHARDEV_FD,
#endif
+ .class_init = char_pipe_class_init,
};
static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend,
@@ -3948,22 +3969,35 @@ static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend,
}
static const CharDriver ringbuf_driver = {
- .instance_size = sizeof(RingBufChardev),
.kind = CHARDEV_BACKEND_KIND_RINGBUF,
.parse = qemu_chr_parse_ringbuf,
- .create = qemu_chr_open_ringbuf,
- .chr_write = ringbuf_chr_write,
- .chr_free = ringbuf_chr_free,
+};
+
+static void char_ringbuf_class_init(ObjectClass *oc, void *data)
+{
+ ChardevClass *cc = CHARDEV_CLASS(oc);
+
+ cc->open = qemu_chr_open_ringbuf;
+ cc->chr_write = ringbuf_chr_write;
+ cc->chr_free = ringbuf_chr_free;
+}
+
+static const TypeInfo char_ringbuf_type_info = {
+ .name = TYPE_CHARDEV_RINGBUF,
+ .parent = TYPE_CHARDEV,
+ .class_init = char_ringbuf_class_init,
+ .instance_size = sizeof(RingBufChardev),
};
/* Bug-compatibility: */
static const CharDriver memory_driver = {
- .instance_size = sizeof(RingBufChardev),
.kind = CHARDEV_BACKEND_KIND_MEMORY,
.parse = qemu_chr_parse_ringbuf,
- .create = qemu_chr_open_ringbuf,
- .chr_write = ringbuf_chr_write,
- .chr_free = ringbuf_chr_free,
+};
+
+static const TypeInfo char_memory_type_info = {
+ .name = TYPE_CHARDEV_MEMORY,
+ .parent = TYPE_CHARDEV_RINGBUF,
};
static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend,
@@ -3982,14 +4016,26 @@ static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend,
}
static const CharDriver mux_driver = {
- .instance_size = sizeof(MuxChardev),
.kind = CHARDEV_BACKEND_KIND_MUX,
.parse = qemu_chr_parse_mux,
- .create = qemu_chr_open_mux,
- .chr_free = mux_chr_free,
- .chr_write = mux_chr_write,
- .chr_accept_input = mux_chr_accept_input,
- .chr_add_watch = mux_chr_add_watch,
+};
+
+static void char_mux_class_init(ObjectClass *oc, void *data)
+{
+ ChardevClass *cc = CHARDEV_CLASS(oc);
+
+ cc->open = qemu_chr_open_mux;
+ cc->chr_free = mux_chr_free;
+ cc->chr_write = mux_chr_write;
+ cc->chr_accept_input = mux_chr_accept_input;
+ cc->chr_add_watch = mux_chr_add_watch;
+}
+
+static const TypeInfo char_mux_type_info = {
+ .name = TYPE_CHARDEV_MUX,
+ .parent = TYPE_CHARDEV,
+ .class_init = char_mux_class_init,
+ .instance_size = sizeof(MuxChardev),
};
static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
@@ -4269,7 +4315,7 @@ Chardev *qemu_chr_new(const char *label, const char *filename)
if (replay_mode != REPLAY_MODE_NONE) {
qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_REPLAY);
}
- if (qemu_chr_replay(chr) && chr->driver->chr_ioctl) {
+ if (qemu_chr_replay(chr) && CHARDEV_GET_CLASS(chr)->chr_ioctl) {
error_report("Replay: ioctl is not supported "
"for serial devices yet");
}
@@ -4282,8 +4328,8 @@ void qemu_chr_fe_set_echo(CharBackend *be, bool echo)
{
Chardev *chr = be->chr;
- if (chr && chr->driver->chr_set_echo) {
- chr->driver->chr_set_echo(chr, echo);
+ if (chr && CHARDEV_GET_CLASS(chr)->chr_set_echo) {
+ CHARDEV_GET_CLASS(chr)->chr_set_echo(chr, echo);
}
}
@@ -4299,8 +4345,8 @@ void qemu_chr_fe_set_open(CharBackend *be, int fe_open)
return;
}
be->fe_open = fe_open;
- if (chr->driver->chr_set_fe_open) {
- chr->driver->chr_set_fe_open(chr, fe_open);
+ if (CHARDEV_GET_CLASS(chr)->chr_set_fe_open) {
+ CHARDEV_GET_CLASS(chr)->chr_set_fe_open(chr, fe_open);
}
}
@@ -4311,11 +4357,11 @@ guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond,
GSource *src;
guint tag;
- if (!s || s->driver->chr_add_watch == NULL) {
+ if (!s || CHARDEV_GET_CLASS(s)->chr_add_watch == NULL) {
return 0;
}
- src = s->driver->chr_add_watch(s, cond);
+ src = CHARDEV_GET_CLASS(s)->chr_add_watch(s, cond);
if (!src) {
return 0;
}
@@ -4331,31 +4377,17 @@ void qemu_chr_fe_disconnect(CharBackend *be)
{
Chardev *chr = be->chr;
- if (chr && chr->driver->chr_disconnect) {
- chr->driver->chr_disconnect(chr);
+ if (chr && CHARDEV_GET_CLASS(chr)->chr_disconnect) {
+ CHARDEV_GET_CLASS(chr)->chr_disconnect(chr);
}
}
-static void qemu_chr_free_common(Chardev *chr)
-{
- if (chr->be) {
- chr->be->chr = NULL;
- }
- g_free(chr->filename);
- g_free(chr->label);
- if (chr->logfd != -1) {
- close(chr->logfd);
- }
- qemu_mutex_destroy(&chr->chr_write_lock);
- g_free(chr);
-}
-
void qemu_chr_free(Chardev *chr)
{
- if (chr->driver->chr_free) {
- chr->driver->chr_free(chr);
+ if (CHARDEV_GET_CLASS(chr)->chr_free) {
+ CHARDEV_GET_CLASS(chr)->chr_free(chr);
}
- qemu_chr_free_common(chr);
+ object_unref(OBJECT(chr));
}
void qemu_chr_delete(Chardev *chr)
@@ -4523,22 +4555,19 @@ QemuOptsList qemu_chardev_opts = {
#ifdef _WIN32
-static Chardev *qmp_chardev_open_file(const CharDriver *driver,
- const char *id,
- ChardevBackend *backend,
- ChardevReturn *ret,
- bool *be_opened,
- Error **errp)
+static void qmp_chardev_open_file(Chardev *chr,
+ ChardevBackend *backend,
+ bool *be_opened,
+ Error **errp)
{
ChardevFile *file = backend->u.file.data;
- ChardevCommon *common = qapi_ChardevFile_base(file);
HANDLE out;
DWORD accessmode;
DWORD flags;
if (file->has_in) {
error_setg(errp, "input file not supported");
- return NULL;
+ return;
}
if (file->has_append && file->append) {
@@ -4555,33 +4584,20 @@ static Chardev *qmp_chardev_open_file(const CharDriver *driver,
FILE_ATTRIBUTE_NORMAL, NULL);
if (out == INVALID_HANDLE_VALUE) {
error_setg(errp, "open %s failed", file->out);
- return NULL;
+ return;
}
- return qemu_chr_open_win_file(driver, out, common, errp);
+
+ qemu_chr_open_win_file(chr, out);
}
-static Chardev *qmp_chardev_open_serial(const CharDriver *driver,
- const char *id,
- ChardevBackend *backend,
- ChardevReturn *ret,
- bool *be_opened,
- Error **errp)
+static void qmp_chardev_open_serial(Chardev *chr,
+ ChardevBackend *backend,
+ bool *be_opened,
+ Error **errp)
{
ChardevHostdev *serial = backend->u.serial.data;
- ChardevCommon *common = qapi_ChardevHostdev_base(serial);
- Chardev *chr;
- chr = qemu_chr_alloc(driver, common, errp);
- if (!chr) {
- return NULL;
- }
-
- if (win_chr_init(chr, serial->device, errp) < 0) {
- qemu_chr_free_common(chr);
- return NULL;
- }
-
- return chr;
+ win_chr_init(chr, serial->device, errp);
}
#else /* WIN32 */
@@ -4598,15 +4614,12 @@ static int qmp_chardev_open_file_source(char *src, int flags,
return fd;
}
-static Chardev *qmp_chardev_open_file(const CharDriver *driver,
- const char *id,
- ChardevBackend *backend,
- ChardevReturn *ret,
- bool *be_opened,
- Error **errp)
+static void qmp_chardev_open_file(Chardev *chr,
+ ChardevBackend *backend,
+ bool *be_opened,
+ Error **errp)
{
ChardevFile *file = backend->u.file.data;
- ChardevCommon *common = qapi_ChardevFile_base(file);
int flags, in = -1, out;
flags = O_WRONLY | O_CREAT | O_BINARY;
@@ -4618,7 +4631,7 @@ static Chardev *qmp_chardev_open_file(const CharDriver *driver,
out = qmp_chardev_open_file_source(file->out, flags, errp);
if (out < 0) {
- return NULL;
+ return;
}
if (file->has_in) {
@@ -4626,70 +4639,76 @@ static Chardev *qmp_chardev_open_file(const CharDriver *driver,
in = qmp_chardev_open_file_source(file->in, flags, errp);
if (in < 0) {
qemu_close(out);
- return NULL;
+ return;
}
}
- return qemu_chr_open_fd(driver, in, out, common, errp);
+ qemu_chr_open_fd(chr, in, out);
}
#ifdef HAVE_CHARDEV_SERIAL
-static Chardev *qmp_chardev_open_serial(const CharDriver *driver,
- const char *id,
- ChardevBackend *backend,
- ChardevReturn *ret,
- bool *be_opened,
- Error **errp)
+static void qmp_chardev_open_serial(Chardev *chr,
+ ChardevBackend *backend,
+ bool *be_opened,
+ Error **errp)
{
ChardevHostdev *serial = backend->u.serial.data;
- ChardevCommon *common = qapi_ChardevHostdev_base(serial);
int fd;
fd = qmp_chardev_open_file_source(serial->device, O_RDWR, errp);
if (fd < 0) {
- return NULL;
+ return;
}
qemu_set_nonblock(fd);
tty_serial_init(fd, 115200, 'N', 8, 1);
- return qemu_chr_open_fd(driver, fd, fd, common, errp);
+ qemu_chr_open_fd(chr, fd, fd);
}
#endif
#ifdef HAVE_CHARDEV_PARPORT
-static Chardev *qmp_chardev_open_parallel(const CharDriver *driver,
- const char *id,
- ChardevBackend *backend,
- ChardevReturn *ret,
- bool *be_opened,
- Error **errp)
+static void qmp_chardev_open_parallel(Chardev *chr,
+ ChardevBackend *backend,
+ bool *be_opened,
+ Error **errp)
{
ChardevHostdev *parallel = backend->u.parallel.data;
- ChardevCommon *common = qapi_ChardevHostdev_base(parallel);
int fd;
fd = qmp_chardev_open_file_source(parallel->device, O_RDWR, errp);
if (fd < 0) {
- return NULL;
+ return;
}
- return qemu_chr_open_pp_fd(driver, fd, common, be_opened, errp);
+ qemu_chr_open_pp_fd(chr, fd, be_opened, errp);
}
static const CharDriver parallel_driver = {
- .instance_size = sizeof(ParallelChardev),
.kind = CHARDEV_BACKEND_KIND_PARALLEL,
.alias = "parport",
.parse = qemu_chr_parse_parallel,
- .create = qmp_chardev_open_parallel,
+};
+
+static void char_parallel_class_init(ObjectClass *oc, void *data)
+{
+ ChardevClass *cc = CHARDEV_CLASS(oc);
+
+ cc->open = qmp_chardev_open_parallel;
#if defined(__linux__)
- .chr_write = null_chr_write,
- .chr_ioctl = pp_ioctl,
- .chr_free = pp_free,
+ cc->chr_write = null_chr_write;
+ cc->chr_ioctl = pp_ioctl;
+ cc->chr_free = pp_free;
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
- .chr_write = null_chr_write,
- .chr_ioctl = pp_ioctl,
/* FIXME: no chr_free */
+ cc->chr_write = null_chr_write;
+ cc->chr_ioctl = pp_ioctl;
#endif
+}
+
+static const TypeInfo char_parallel_type_info = {
+ .name = TYPE_CHARDEV_PARALLEL,
+ .parent = TYPE_CHARDEV,
+ .instance_size = sizeof(ParallelChardev),
+ .class_init = char_parallel_class_init,
};
#endif
@@ -4698,45 +4717,63 @@ static const CharDriver parallel_driver = {
static const CharDriver file_driver = {
.kind = CHARDEV_BACKEND_KIND_FILE,
.parse = qemu_chr_parse_file_out,
- .create = qmp_chardev_open_file,
+};
+
+static void char_file_class_init(ObjectClass *oc, void *data)
+{
+ ChardevClass *cc = CHARDEV_CLASS(oc);
+
+ cc->open = qmp_chardev_open_file;
#ifdef _WIN32
- sizeof(WinChardev),
- .chr_write = win_chr_write,
/* FIXME: no chr_free */
+ cc->chr_free = NULL;
+#endif
+}
+
+static const TypeInfo char_file_type_info = {
+ .name = TYPE_CHARDEV_FILE,
+#ifdef _WIN32
+ .parent = TYPE_CHARDEV_WIN,
#else
- sizeof(FDChardev),
- .chr_add_watch = fd_chr_add_watch,
- .chr_write = fd_chr_write,
- .chr_update_read_handler = fd_chr_update_read_handler,
- .chr_free = fd_chr_free,
+ .parent = TYPE_CHARDEV_FD,
#endif
+ .class_init = char_file_class_init,
};
#ifdef HAVE_CHARDEV_SERIAL
+
static const CharDriver serial_driver = {
.kind = CHARDEV_BACKEND_KIND_SERIAL,
.alias = "tty",
.parse = qemu_chr_parse_serial,
- .create = qmp_chardev_open_serial,
+};
+
+static void char_serial_class_init(ObjectClass *oc, void *data)
+{
+ ChardevClass *cc = CHARDEV_CLASS(oc);
+
+ cc->open = qmp_chardev_open_serial;
+#ifndef _WIN32
+ cc->chr_ioctl = tty_serial_ioctl;
+ cc->chr_free = qemu_chr_free_tty;
+#endif
+}
+
+static const TypeInfo char_serial_type_info = {
+ .name = TYPE_CHARDEV_SERIAL,
#ifdef _WIN32
- sizeof(WinChardev),
- .chr_write = win_chr_write,
- .chr_free = win_chr_free,
+ .parent = TYPE_CHARDEV_WIN,
#else
- sizeof(FDChardev),
- .chr_add_watch = fd_chr_add_watch,
- .chr_write = fd_chr_write,
- .chr_update_read_handler = fd_chr_update_read_handler,
- .chr_ioctl = tty_serial_ioctl,
- .chr_free = qemu_chr_free_tty,
+ .parent = TYPE_CHARDEV_FD,
#endif
+ .class_init = char_serial_class_init,
};
#endif
static gboolean socket_reconnect_timeout(gpointer opaque)
{
- Chardev *chr = opaque;
- SocketChardev *s = opaque;
+ Chardev *chr = CHARDEV(opaque);
+ SocketChardev *s = SOCKET_CHARDEV(opaque);
QIOChannelSocket *sioc;
s->reconnect_timer = 0;
@@ -4754,15 +4791,12 @@ static gboolean socket_reconnect_timeout(gpointer opaque)
return false;
}
-static Chardev *qmp_chardev_open_socket(const CharDriver *driver,
- const char *id,
- ChardevBackend *backend,
- ChardevReturn *ret,
- bool *be_opened,
- Error **errp)
+static void qmp_chardev_open_socket(Chardev *chr,
+ ChardevBackend *backend,
+ bool *be_opened,
+ Error **errp)
{
- Chardev *chr;
- SocketChardev *s;
+ SocketChardev *s = SOCKET_CHARDEV(chr);
ChardevSocket *sock = backend->u.socket.data;
SocketAddress *addr = sock->addr;
bool do_nodelay = sock->has_nodelay ? sock->nodelay : false;
@@ -4770,15 +4804,8 @@ static Chardev *qmp_chardev_open_socket(const CharDriver *driver,
bool is_telnet = sock->has_telnet ? sock->telnet : false;
bool is_waitconnect = sock->has_wait ? sock->wait : false;
int64_t reconnect = sock->has_reconnect ? sock->reconnect : 0;
- ChardevCommon *common = qapi_ChardevSocket_base(sock);
QIOChannelSocket *sioc = NULL;
- chr = qemu_chr_alloc(driver, common, errp);
- if (!chr) {
- return NULL;
- }
- s = (SocketChardev *)chr;
-
s->is_unix = addr->type == SOCKET_ADDRESS_KIND_UNIX;
s->is_listen = is_listen;
s->is_telnet = is_telnet;
@@ -4870,82 +4897,92 @@ static Chardev *qmp_chardev_open_socket(const CharDriver *driver,
}
}
- return chr;
+ return;
- error:
+error:
if (sioc) {
object_unref(OBJECT(sioc));
}
if (s->tls_creds) {
object_unref(OBJECT(s->tls_creds));
}
- qemu_chr_free_common(chr);
- return NULL;
}
static const CharDriver socket_driver = {
- .instance_size = sizeof(SocketChardev),
.kind = CHARDEV_BACKEND_KIND_SOCKET,
.parse = qemu_chr_parse_socket,
- .create = qmp_chardev_open_socket,
- .chr_wait_connected = tcp_chr_wait_connected,
- .chr_write = tcp_chr_write,
- .chr_sync_read = tcp_chr_sync_read,
- .chr_disconnect = tcp_chr_disconnect,
- .get_msgfds = tcp_get_msgfds,
- .set_msgfds = tcp_set_msgfds,
- .chr_add_client = tcp_chr_add_client,
- .chr_add_watch = tcp_chr_add_watch,
- .chr_update_read_handler = tcp_chr_update_read_handler,
- .chr_free = tcp_chr_free,
};
-static Chardev *qmp_chardev_open_udp(const CharDriver *driver,
- const char *id,
- ChardevBackend *backend,
- ChardevReturn *ret,
- bool *be_opened,
- Error **errp)
+static void char_socket_class_init(ObjectClass *oc, void *data)
+{
+ ChardevClass *cc = CHARDEV_CLASS(oc);
+
+ cc->open = qmp_chardev_open_socket;
+ cc->chr_wait_connected = tcp_chr_wait_connected;
+ cc->chr_write = tcp_chr_write;
+ cc->chr_sync_read = tcp_chr_sync_read;
+ cc->chr_disconnect = tcp_chr_disconnect;
+ cc->get_msgfds = tcp_get_msgfds;
+ cc->set_msgfds = tcp_set_msgfds;
+ cc->chr_add_client = tcp_chr_add_client;
+ cc->chr_add_watch = tcp_chr_add_watch;
+ cc->chr_update_read_handler = tcp_chr_update_read_handler;
+ cc->chr_free = tcp_chr_free;
+}
+
+static const TypeInfo char_socket_type_info = {
+ .name = TYPE_CHARDEV_SOCKET,
+ .parent = TYPE_CHARDEV,
+ .instance_size = sizeof(SocketChardev),
+ .class_init = char_socket_class_init,
+};
+
+static void qmp_chardev_open_udp(Chardev *chr,
+ ChardevBackend *backend,
+ bool *be_opened,
+ Error **errp)
{
ChardevUdp *udp = backend->u.udp.data;
- ChardevCommon *common = qapi_ChardevUdp_base(udp);
QIOChannelSocket *sioc = qio_channel_socket_new();
char *name;
- Chardev *chr;
- UdpChardev *s;
+ UdpChardev *s = UDP_CHARDEV(chr);
if (qio_channel_socket_dgram_sync(sioc,
udp->local, udp->remote,
errp) < 0) {
object_unref(OBJECT(sioc));
- return NULL;
- }
-
- chr = qemu_chr_alloc(driver, common, errp);
- if (!chr) {
- return NULL;
+ return;
}
name = g_strdup_printf("chardev-udp-%s", chr->label);
qio_channel_set_name(QIO_CHANNEL(sioc), name);
g_free(name);
- s = (UdpChardev *)chr;
s->ioc = QIO_CHANNEL(sioc);
/* be isn't opened until we get a connection */
*be_opened = false;
-
- return chr;
}
static const CharDriver udp_driver = {
- .instance_size = sizeof(UdpChardev),
.kind = CHARDEV_BACKEND_KIND_UDP,
.parse = qemu_chr_parse_udp,
- .create = qmp_chardev_open_udp,
- .chr_write = udp_chr_write,
- .chr_update_read_handler = udp_chr_update_read_handler,
- .chr_free = udp_chr_free,
+};
+
+static void char_udp_class_init(ObjectClass *oc, void *data)
+{
+ ChardevClass *cc = CHARDEV_CLASS(oc);
+
+ cc->open = qmp_chardev_open_udp;
+ cc->chr_write = udp_chr_write;
+ cc->chr_update_read_handler = udp_chr_update_read_handler;
+ cc->chr_free = udp_chr_free;
+}
+
+static const TypeInfo char_udp_type_info = {
+ .name = TYPE_CHARDEV_UDP,
+ .parent = TYPE_CHARDEV,
+ .instance_size = sizeof(UdpChardev),
+ .class_init = char_udp_class_init,
};
bool qemu_chr_has_feature(Chardev *chr,
@@ -4960,47 +4997,96 @@ void qemu_chr_set_feature(Chardev *chr,
return set_bit(feature, chr->features);
}
-ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
- Error **errp)
+static const ChardevClass *char_get_class(const char *driver, Error **errp)
+{
+ ObjectClass *oc;
+ const ChardevClass *cc;
+ char *typename = g_strdup_printf("chardev-%s", driver);
+
+ oc = object_class_by_name(typename);
+ g_free(typename);
+
+ if (!object_class_dynamic_cast(oc, TYPE_CHARDEV)) {
+ error_setg(errp, "'%s' is not a valid char driver name", driver);
+ return NULL;
+ }
+
+ if (object_class_is_abstract(oc)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
+ "abstract device type");
+ return NULL;
+ }
+
+ cc = CHARDEV_CLASS(oc);
+ if (cc->internal) {
+ error_setg(errp, "'%s' is not a valid char driver name", driver);
+ return NULL;
+ }
+
+ return cc;
+}
+
+Chardev *qemu_chardev_new(const char *id, const char *typename,
+ ChardevBackend *backend, Error **errp)
{
- ChardevReturn *ret = g_new0(ChardevReturn, 1);
Chardev *chr = NULL;
- const CharDriver *cd;
Error *local_err = NULL;
bool be_opened = true;
- chr = qemu_chr_find(id);
- if (chr) {
- error_setg(errp, "Chardev '%s' already exists", id);
- goto out_error;
- }
+ assert(g_str_has_prefix(typename, "chardev-"));
- cd = (int)backend->type >= 0 && backend->type < ARRAY_SIZE(backends) ?
- backends[backend->type] : NULL;
- if (cd == NULL) {
- error_setg(errp, "chardev backend not available");
- goto out_error;
- }
+ chr = CHARDEV(object_new(typename));
+ chr->label = g_strdup(id);
- chr = cd->create(cd, id, backend, ret, &be_opened, &local_err);
+ qemu_char_open(chr, backend, &be_opened, &local_err);
if (local_err) {
error_propagate(errp, local_err);
- goto out_error;
+ object_unref(OBJECT(chr));
+ return NULL;
}
- chr->label = g_strdup(id);
if (!chr->filename) {
- chr->filename = g_strdup(ChardevBackendKind_lookup[backend->type]);
+ chr->filename = g_strdup(typename + 8);
}
if (be_opened) {
qemu_chr_be_event(chr, CHR_EVENT_OPENED);
}
+
+ return chr;
+}
+
+ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
+ Error **errp)
+{
+ const ChardevClass *cc;
+ ChardevReturn *ret;
+ Chardev *chr;
+
+ chr = qemu_chr_find(id);
+ if (chr) {
+ error_setg(errp, "Chardev '%s' already exists", id);
+ return NULL;
+ }
+
+ cc = char_get_class(ChardevBackendKind_lookup[backend->type], errp);
+ if (!cc) {
+ return NULL;
+ }
+
+ chr = qemu_chardev_new(id, object_class_get_name(OBJECT_CLASS(cc)),
+ backend, errp);
+ if (!chr) {
+ return NULL;
+ }
+
+ ret = g_new0(ChardevReturn, 1);
+ if (CHARDEV_IS_PTY(chr)) {
+ ret->pty = g_strdup(chr->filename + 4);
+ ret->has_pty = true;
+ }
+
QTAILQ_INSERT_TAIL(&chardevs, chr, next);
return ret;
-
-out_error:
- g_free(ret);
- return NULL;
}
void qmp_chardev_remove(const char *id, Error **errp)
@@ -5035,33 +5121,44 @@ void qemu_chr_cleanup(void)
static void register_types(void)
{
- static const CharDriver *drivers[] = {
- &null_driver,
- &socket_driver,
- &udp_driver,
- &ringbuf_driver,
- &file_driver,
- &stdio_driver,
+ static const struct {
+ const CharDriver *driver;
+ const TypeInfo *type;
+ } chardevs[] = {
+ { &null_driver, &char_null_type_info },
+ { &socket_driver, &char_socket_type_info },
+ { &udp_driver, &char_udp_type_info },
+ { &ringbuf_driver, &char_ringbuf_type_info },
+ { &file_driver, &char_file_type_info },
+ { &stdio_driver, &char_stdio_type_info },
#ifdef HAVE_CHARDEV_SERIAL
- &serial_driver,
+ { &serial_driver, &char_serial_type_info },
#endif
#ifdef HAVE_CHARDEV_PARPORT
- &parallel_driver,
+ { &parallel_driver, &char_parallel_type_info },
#endif
#ifdef HAVE_CHARDEV_PTY
- &pty_driver,
+ { &pty_driver, &char_pty_type_info },
#endif
#ifdef _WIN32
- &console_driver,
+ { &console_driver, &char_console_type_info },
#endif
- &pipe_driver,
- &mux_driver,
- &memory_driver
+ { &pipe_driver, &char_pipe_type_info },
+ { &mux_driver, &char_mux_type_info },
+ { &memory_driver, &char_memory_type_info }
};
int i;
- for (i = 0; i < ARRAY_SIZE(drivers); i++) {
- register_char_driver(drivers[i]);
+ type_register_static(&char_type_info);
+#ifndef _WIN32
+ type_register_static(&char_fd_type_info);
+#else
+ type_register_static(&char_win_type_info);
+ type_register_static(&char_win_stdio_type_info);
+#endif
+ for (i = 0; i < ARRAY_SIZE(chardevs); i++) {
+ type_register_static(chardevs[i].type);
+ register_char_driver(chardevs[i].driver);
}
/* this must be done after machine init, since we register FEs with muxes