Update to git snapshot 525e3df as we prepare for 0.15.0 release
This commit is contained in:
parent
2af28c1745
commit
0c846be9ae
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@ qemu-kvm-0.13.0-25fdf4a.tar.gz
|
||||
/qemu-kvm-0.13.0.tar.gz
|
||||
/qemu-kvm-0.14.0-3593e6b.tar.gz
|
||||
/qemu-kvm-0.14.0-7aa8c46.tar.gz
|
||||
/qemu-kvm-0.15.0-525e3df.tar.gz
|
||||
|
@ -1,143 +0,0 @@
|
||||
>From fd04276a00b172e6fbba3e3c72b1d13a0f179414 Mon Sep 17 00:00:00 2001
|
||||
From: Alon Levy <alevy@redhat.com>
|
||||
Date: Wed, 16 Mar 2011 15:21:03 +0100
|
||||
Subject: [PATCH 1/4] qxl/spice-display: move pipe to ssd
|
||||
|
||||
This moves the int pipe[2] and pthread_t main data from the
|
||||
PCIQXLDevice struct to the SimpleSpiceDisplay. This will let us
|
||||
reuse it in the next patch for both -spice with no -qxl usage and
|
||||
for vga mode from qxl.
|
||||
|
||||
Also move the pipe creation function (which is effectively completely rewritten
|
||||
by this patch anyways) from hw/qxl.c to ui/spice-display.c, since
|
||||
spice-display will depend on it after the next patch and qemu can be build
|
||||
with ui/spice-display.c in combination with no hw/qxl.c.
|
||||
---
|
||||
hw/qxl.c | 22 +++++-----------------
|
||||
hw/qxl.h | 4 ----
|
||||
ui/spice-display.c | 21 +++++++++++++++++++++
|
||||
ui/spice-display.h | 8 ++++++++
|
||||
4 files changed, 34 insertions(+), 21 deletions(-)
|
||||
|
||||
diff --git a/hw/qxl.c b/hw/qxl.c
|
||||
index fe4212b..201698f 100644
|
||||
--- a/hw/qxl.c
|
||||
+++ b/hw/qxl.c
|
||||
@@ -1062,7 +1062,7 @@ static void pipe_read(void *opaque)
|
||||
int len;
|
||||
|
||||
do {
|
||||
- len = read(d->pipe[0], &dummy, sizeof(dummy));
|
||||
+ len = read(d->ssd.pipe[0], &dummy, sizeof(dummy));
|
||||
} while (len == sizeof(dummy));
|
||||
qxl_set_irq(d);
|
||||
}
|
||||
@@ -1078,10 +1078,11 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
|
||||
if ((old_pending & le_events) == le_events) {
|
||||
return;
|
||||
}
|
||||
- if (pthread_self() == d->main) {
|
||||
+ if (pthread_self() == d->ssd.main) {
|
||||
+ /* running in io_thread thread */
|
||||
qxl_set_irq(d);
|
||||
} else {
|
||||
- if (write(d->pipe[1], d, 1) != 1) {
|
||||
+ if (write(d->ssd.pipe[1], d, 1) != 1) {
|
||||
dprint(d, 1, "%s: write to pipe failed\n", __FUNCTION__);
|
||||
}
|
||||
}
|
||||
@@ -1089,20 +1090,7 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
|
||||
|
||||
static void init_pipe_signaling(PCIQXLDevice *d)
|
||||
{
|
||||
- if (pipe(d->pipe) < 0) {
|
||||
- dprint(d, 1, "%s: pipe creation failed\n", __FUNCTION__);
|
||||
- return;
|
||||
- }
|
||||
-#ifdef CONFIG_IOTHREAD
|
||||
- fcntl(d->pipe[0], F_SETFL, O_NONBLOCK);
|
||||
-#else
|
||||
- fcntl(d->pipe[0], F_SETFL, O_NONBLOCK /* | O_ASYNC */);
|
||||
-#endif
|
||||
- fcntl(d->pipe[1], F_SETFL, O_NONBLOCK);
|
||||
- fcntl(d->pipe[0], F_SETOWN, getpid());
|
||||
-
|
||||
- d->main = pthread_self();
|
||||
- qemu_set_fd_handler(d->pipe[0], pipe_read, NULL, d);
|
||||
+ qxl_create_server_to_iothread_pipe(&d->ssd, pipe_read);
|
||||
}
|
||||
|
||||
/* graphics console */
|
||||
diff --git a/hw/qxl.h b/hw/qxl.h
|
||||
index f6c450d..701245f 100644
|
||||
--- a/hw/qxl.h
|
||||
+++ b/hw/qxl.h
|
||||
@@ -55,10 +55,6 @@ typedef struct PCIQXLDevice {
|
||||
} guest_surfaces;
|
||||
QXLPHYSICAL guest_cursor;
|
||||
|
||||
- /* thread signaling */
|
||||
- pthread_t main;
|
||||
- int pipe[2];
|
||||
-
|
||||
/* ram pci bar */
|
||||
QXLRam *ram;
|
||||
VGACommonState vga;
|
||||
diff --git a/ui/spice-display.c b/ui/spice-display.c
|
||||
index 020b423..ec6e0cb 100644
|
||||
--- a/ui/spice-display.c
|
||||
+++ b/ui/spice-display.c
|
||||
@@ -394,6 +394,27 @@ static DisplayChangeListener display_listener = {
|
||||
.dpy_refresh = display_refresh,
|
||||
};
|
||||
|
||||
+void qxl_create_server_to_iothread_pipe(SimpleSpiceDisplay *ssd,
|
||||
+ IOHandler *pipe_read)
|
||||
+{
|
||||
+ if (pipe(ssd->pipe) < 0) {
|
||||
+ fprintf(stderr, "%s: pipe creation failed\n", __FUNCTION__);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+#ifdef CONFIG_IOTHREAD
|
||||
+ fcntl(ssd->pipe[0], F_SETFL, O_NONBLOCK);
|
||||
+#else
|
||||
+ fcntl(ssd->pipe[0], F_SETFL, O_NONBLOCK /* | O_ASYNC */);
|
||||
+#endif
|
||||
+ fcntl(ssd->pipe[1], F_SETFL, O_NONBLOCK);
|
||||
+
|
||||
+ fcntl(ssd->pipe[0], F_SETOWN, getpid());
|
||||
+
|
||||
+ qemu_set_fd_handler(ssd->pipe[0], pipe_read, NULL, ssd);
|
||||
+ ssd->main = pthread_self();
|
||||
+}
|
||||
+
|
||||
void qemu_spice_display_init(DisplayState *ds)
|
||||
{
|
||||
assert(sdpy.ds == NULL);
|
||||
diff --git a/ui/spice-display.h b/ui/spice-display.h
|
||||
index aef0464..3e6cf7c 100644
|
||||
--- a/ui/spice-display.h
|
||||
+++ b/ui/spice-display.h
|
||||
@@ -43,6 +43,11 @@ typedef struct SimpleSpiceDisplay {
|
||||
QXLRect dirty;
|
||||
int notify;
|
||||
int running;
|
||||
+
|
||||
+ /* thread signaling - used both in qxl (in vga mode
|
||||
+ * and in native mode) and without qxl */
|
||||
+ pthread_t main;
|
||||
+ int pipe[2]; /* to iothread */
|
||||
} SimpleSpiceDisplay;
|
||||
|
||||
typedef struct SimpleSpiceUpdate {
|
||||
@@ -66,3 +71,6 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
|
||||
int x, int y, int w, int h);
|
||||
void qemu_spice_display_resize(SimpleSpiceDisplay *ssd);
|
||||
void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd);
|
||||
+/* used by both qxl and spice-display */
|
||||
+void qxl_create_server_to_iothread_pipe(SimpleSpiceDisplay *ssd,
|
||||
+ IOHandler *pipe_read);
|
||||
--
|
||||
1.7.3.2
|
||||
|
@ -1,312 +0,0 @@
|
||||
>From 97e291086fef45762e0278e85ab1d231a9902bbb Mon Sep 17 00:00:00 2001
|
||||
From: Uri Lublin <uril@redhat.com>
|
||||
Date: Wed, 16 Mar 2011 15:43:45 +0100
|
||||
Subject: [PATCH 2/4] qxl: implement get_command in vga mode without locks
|
||||
|
||||
This patch and the next drop the requirement to lose the global qemu
|
||||
mutex during dispatcher calls. This patch enables it, the next drops
|
||||
the unlock/lock pairs around dispatcher calls.
|
||||
|
||||
The current solution of dropping the locks is buggy:
|
||||
* it allows multiple dispatcher calls from two vcpu threads, the
|
||||
dispatcher doesn't handle that by design (single fd, not locked, can't
|
||||
handle writes from two threads)
|
||||
* it requires us to keep track of cpu_single_env, which is magic.
|
||||
|
||||
The solution implemented in this patch and the next (the next just
|
||||
drops the locks, this patch allows that to work):
|
||||
* the only operation that needed locking was qemu_create_simple_update,
|
||||
* it required locking because it was called from the spice-server thread.
|
||||
* do it in the iothread by reusing the existing pipe used for set_irq.
|
||||
|
||||
The current flow implemented is now:
|
||||
spice-server thread:
|
||||
qxl.c:interface_get_command (called either by polling or from wakeup)
|
||||
if update!=NULL:
|
||||
waiting_for_update=0
|
||||
update=NULL
|
||||
return update
|
||||
else:
|
||||
if not waiting_for_update:
|
||||
waiting_for_update=1
|
||||
write to pipe, which is read by iothread (main thread)
|
||||
|
||||
iothread:
|
||||
wakeup from select,
|
||||
qxl.c:pipe_read
|
||||
update=qemu_create_simple_update()
|
||||
wakeup spice-server thread by calling d.worker->wakeup(d.worker)
|
||||
---
|
||||
hw/qxl.c | 81 +++++++++++++++++++++++++++++++++++++++------------
|
||||
ui/spice-display.c | 75 +++++++++++++++++++++++++++++++++++++++++++----
|
||||
ui/spice-display.h | 16 ++++++++++
|
||||
3 files changed, 146 insertions(+), 26 deletions(-)
|
||||
|
||||
diff --git a/hw/qxl.c b/hw/qxl.c
|
||||
index 201698f..64580f1 100644
|
||||
--- a/hw/qxl.c
|
||||
+++ b/hw/qxl.c
|
||||
@@ -340,7 +340,6 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
|
||||
static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
|
||||
{
|
||||
PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
|
||||
- SimpleSpiceUpdate *update;
|
||||
QXLCommandRing *ring;
|
||||
QXLCommand *cmd;
|
||||
int notify;
|
||||
@@ -348,16 +347,25 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
|
||||
switch (qxl->mode) {
|
||||
case QXL_MODE_VGA:
|
||||
dprint(qxl, 2, "%s: vga\n", __FUNCTION__);
|
||||
- update = qemu_spice_create_update(&qxl->ssd);
|
||||
- if (update == NULL) {
|
||||
- return false;
|
||||
+ if (qxl_vga_mode_get_command(&qxl->ssd, ext)) {
|
||||
+ qxl_log_command(qxl, "vga", ext);
|
||||
+ return true;
|
||||
}
|
||||
- *ext = update->ext;
|
||||
- qxl_log_command(qxl, "vga", ext);
|
||||
- return true;
|
||||
+ return false;
|
||||
case QXL_MODE_COMPAT:
|
||||
case QXL_MODE_NATIVE:
|
||||
case QXL_MODE_UNDEFINED:
|
||||
+ /* flush any existing updates that we didn't send to the guest.
|
||||
+ * since update != NULL it means the server didn't get it, and
|
||||
+ * because we changed mode to != QXL_MODE_VGA, it won't. */
|
||||
+ if (qxl->ssd.update != NULL) {
|
||||
+ if (qxl->ssd.update != QXL_EMPTY_UPDATE) {
|
||||
+ qemu_spice_destroy_update(&qxl->ssd, qxl->ssd.update);
|
||||
+ }
|
||||
+ qxl->ssd.update = NULL;
|
||||
+ qxl->ssd.waiting_for_update = 0;
|
||||
+ }
|
||||
+ /* */
|
||||
dprint(qxl, 2, "%s: %s\n", __FUNCTION__,
|
||||
qxl->cmdflags ? "compat" : "native");
|
||||
ring = &qxl->ram->cmd_ring;
|
||||
@@ -1057,17 +1065,50 @@ static void qxl_map(PCIDevice *pci, int region_num,
|
||||
|
||||
static void pipe_read(void *opaque)
|
||||
{
|
||||
- PCIQXLDevice *d = opaque;
|
||||
- char dummy;
|
||||
- int len;
|
||||
-
|
||||
- do {
|
||||
- len = read(d->ssd.pipe[0], &dummy, sizeof(dummy));
|
||||
- } while (len == sizeof(dummy));
|
||||
- qxl_set_irq(d);
|
||||
+ SimpleSpiceDisplay *ssd = opaque;
|
||||
+ unsigned char cmd;
|
||||
+ int len, set_irq = 0;
|
||||
+ int create_update = 0;
|
||||
+
|
||||
+ while (1) {
|
||||
+ cmd = 0;
|
||||
+ len = read(ssd->pipe[0], &cmd, sizeof(cmd));
|
||||
+ if (len < 0) {
|
||||
+ if (errno == EINTR) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (errno == EAGAIN) {
|
||||
+ break;
|
||||
+ }
|
||||
+ perror("qxl: pipe_read: read failed");
|
||||
+ break;
|
||||
+ }
|
||||
+ switch (cmd) {
|
||||
+ case QXL_SERVER_SET_IRQ:
|
||||
+ set_irq = 1;
|
||||
+ break;
|
||||
+ case QXL_SERVER_CREATE_UPDATE:
|
||||
+ create_update = 1;
|
||||
+ break;
|
||||
+ default:
|
||||
+ fprintf(stderr, "%s: unknown cmd %u\n", __FUNCTION__, cmd);
|
||||
+ abort();
|
||||
+ }
|
||||
+ }
|
||||
+ /* no need to do either operation more than once */
|
||||
+ if (create_update) {
|
||||
+ assert(ssd->update == NULL);
|
||||
+ ssd->update = qemu_spice_create_update(ssd);
|
||||
+ if (ssd->update == NULL) {
|
||||
+ ssd->update = QXL_EMPTY_UPDATE;
|
||||
+ }
|
||||
+ ssd->worker->wakeup(ssd->worker);
|
||||
+ }
|
||||
+ if (set_irq) {
|
||||
+ qxl_set_irq(container_of(ssd, PCIQXLDevice, ssd));
|
||||
+ }
|
||||
}
|
||||
|
||||
-/* called from spice server thread context only */
|
||||
static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
|
||||
{
|
||||
uint32_t old_pending;
|
||||
@@ -1082,9 +1123,11 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
|
||||
/* running in io_thread thread */
|
||||
qxl_set_irq(d);
|
||||
} else {
|
||||
- if (write(d->ssd.pipe[1], d, 1) != 1) {
|
||||
- dprint(d, 1, "%s: write to pipe failed\n", __FUNCTION__);
|
||||
- }
|
||||
+ /* called from spice-server thread */
|
||||
+ int ret;
|
||||
+ unsigned char ack = QXL_SERVER_SET_IRQ;
|
||||
+ ret = write(d->ssd.pipe[1], &ack, 1);
|
||||
+ assert(ret == 1);
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/ui/spice-display.c b/ui/spice-display.c
|
||||
index ec6e0cb..bdd14b8 100644
|
||||
--- a/ui/spice-display.c
|
||||
+++ b/ui/spice-display.c
|
||||
@@ -294,18 +294,39 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
|
||||
info->n_surfaces = NUM_SURFACES;
|
||||
}
|
||||
|
||||
+/* Called from spice server thread context (via interface_get_command) */
|
||||
+int qxl_vga_mode_get_command(
|
||||
+ SimpleSpiceDisplay *ssd, struct QXLCommandExt *ext)
|
||||
+{
|
||||
+ SimpleSpiceUpdate *update;
|
||||
+ unsigned char req;
|
||||
+ int r;
|
||||
+
|
||||
+ update = ssd->update;
|
||||
+ if (update != NULL) {
|
||||
+ ssd->waiting_for_update = 0;
|
||||
+ ssd->update = NULL;
|
||||
+ if (update != QXL_EMPTY_UPDATE) {
|
||||
+ *ext = update->ext;
|
||||
+ return true;
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (!ssd->waiting_for_update) {
|
||||
+ ssd->waiting_for_update = 1;
|
||||
+ req = QXL_SERVER_CREATE_UPDATE;
|
||||
+ r = write(ssd->pipe[1], &req , 1);
|
||||
+ assert(r == 1);
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
|
||||
{
|
||||
SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
|
||||
- SimpleSpiceUpdate *update;
|
||||
|
||||
dprint(3, "%s:\n", __FUNCTION__);
|
||||
- update = qemu_spice_create_update(ssd);
|
||||
- if (update == NULL) {
|
||||
- return false;
|
||||
- }
|
||||
- *ext = update->ext;
|
||||
- return true;
|
||||
+ return qxl_vga_mode_get_command(ssd, ext);
|
||||
}
|
||||
|
||||
static int interface_req_cmd_notification(QXLInstance *sin)
|
||||
@@ -394,6 +415,45 @@ static DisplayChangeListener display_listener = {
|
||||
.dpy_refresh = display_refresh,
|
||||
};
|
||||
|
||||
+static void pipe_read(void *opaque)
|
||||
+{
|
||||
+ SimpleSpiceDisplay *ssd = opaque;
|
||||
+ unsigned char cmd;
|
||||
+ int len, create_update = 0;
|
||||
+
|
||||
+ while (1) {
|
||||
+ cmd = 0;
|
||||
+ len = read(ssd->pipe[0], &cmd, sizeof(cmd));
|
||||
+ if (len < 0) {
|
||||
+ if (errno == EINTR) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (errno == EAGAIN) {
|
||||
+ break;
|
||||
+ }
|
||||
+ perror("qxl: pipe_read: read failed");
|
||||
+ break;
|
||||
+ }
|
||||
+ switch (cmd) {
|
||||
+ case QXL_SERVER_CREATE_UPDATE:
|
||||
+ create_update = 1;
|
||||
+ break;
|
||||
+ default:
|
||||
+ fprintf(stderr, "%s: unknown cmd %u\n", __FUNCTION__, cmd);
|
||||
+ abort();
|
||||
+ }
|
||||
+ }
|
||||
+ /* no need to do this more than once */
|
||||
+ if (create_update) {
|
||||
+ assert(ssd->update == NULL);
|
||||
+ ssd->update = qemu_spice_create_update(ssd);
|
||||
+ if (ssd->update == NULL) {
|
||||
+ ssd->update = QXL_EMPTY_UPDATE;
|
||||
+ }
|
||||
+ ssd->worker->wakeup(ssd->worker);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void qxl_create_server_to_iothread_pipe(SimpleSpiceDisplay *ssd,
|
||||
IOHandler *pipe_read)
|
||||
{
|
||||
@@ -427,6 +487,7 @@ void qemu_spice_display_init(DisplayState *ds)
|
||||
qemu_spice_add_interface(&sdpy.qxl.base);
|
||||
assert(sdpy.worker);
|
||||
|
||||
+ qxl_create_server_to_iothread_pipe(&sdpy, pipe_read);
|
||||
qemu_add_vm_change_state_handler(qemu_spice_vm_change_state_handler, &sdpy);
|
||||
qemu_spice_create_host_memslot(&sdpy);
|
||||
qemu_spice_create_host_primary(&sdpy);
|
||||
diff --git a/ui/spice-display.h b/ui/spice-display.h
|
||||
index 3e6cf7c..2be6a34 100644
|
||||
--- a/ui/spice-display.h
|
||||
+++ b/ui/spice-display.h
|
||||
@@ -31,6 +31,15 @@
|
||||
|
||||
#define NUM_SURFACES 1024
|
||||
|
||||
+/* For commands/requests from server thread to iothread */
|
||||
+#define QXL_EMPTY_UPDATE ((void *)-1)
|
||||
+enum {
|
||||
+ QXL_SERVER_SET_IRQ = 1,
|
||||
+ QXL_SERVER_CREATE_UPDATE,
|
||||
+};
|
||||
+
|
||||
+struct SimpleSpiceUpdate;
|
||||
+
|
||||
typedef struct SimpleSpiceDisplay {
|
||||
DisplayState *ds;
|
||||
void *buf;
|
||||
@@ -48,6 +57,10 @@ typedef struct SimpleSpiceDisplay {
|
||||
* and in native mode) and without qxl */
|
||||
pthread_t main;
|
||||
int pipe[2]; /* to iothread */
|
||||
+
|
||||
+ /* ssd updates (one request/command at a time) */
|
||||
+ struct SimpleSpiceUpdate *update;
|
||||
+ int waiting_for_update;
|
||||
} SimpleSpiceDisplay;
|
||||
|
||||
typedef struct SimpleSpiceUpdate {
|
||||
@@ -71,6 +84,9 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
|
||||
int x, int y, int w, int h);
|
||||
void qemu_spice_display_resize(SimpleSpiceDisplay *ssd);
|
||||
void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd);
|
||||
+/* shared with qxl.c in vga mode and ui/spice-display (no qxl mode) */
|
||||
+int qxl_vga_mode_get_command(
|
||||
+ SimpleSpiceDisplay *ssd, struct QXLCommandExt *ext);
|
||||
/* used by both qxl and spice-display */
|
||||
void qxl_create_server_to_iothread_pipe(SimpleSpiceDisplay *ssd,
|
||||
IOHandler *pipe_read);
|
||||
--
|
||||
1.7.3.2
|
||||
|
@ -1,148 +0,0 @@
|
||||
>From d413b3c36cbd9820c5b9492b52caa421abccf745 Mon Sep 17 00:00:00 2001
|
||||
From: Alon Levy <alevy@redhat.com>
|
||||
Date: Wed, 16 Mar 2011 15:46:22 +0100
|
||||
Subject: [PATCH 3/4] qxl/spice: remove qemu_mutex_{un,}lock_iothread around dispatcher
|
||||
|
||||
with the previous patch making sure get_command no longer needs to lock,
|
||||
there is no reason to drop the qemu iothread mutex in qxl.c and in
|
||||
ui/spice-display.c
|
||||
|
||||
The only location where the lock remains are the cursor related callbacks,
|
||||
that path is currently broken. It is only triggered if running spice and sdl,
|
||||
which is broken already before that.
|
||||
---
|
||||
hw/qxl.c | 8 --------
|
||||
ui/spice-display.c | 19 +++----------------
|
||||
2 files changed, 3 insertions(+), 24 deletions(-)
|
||||
|
||||
diff --git a/hw/qxl.c b/hw/qxl.c
|
||||
index 64580f1..cf3c938 100644
|
||||
--- a/hw/qxl.c
|
||||
+++ b/hw/qxl.c
|
||||
@@ -670,10 +670,8 @@ static void qxl_hard_reset(PCIQXLDevice *d, int loadvm)
|
||||
dprint(d, 1, "%s: start%s\n", __FUNCTION__,
|
||||
loadvm ? " (loadvm)" : "");
|
||||
|
||||
- qemu_mutex_unlock_iothread();
|
||||
d->ssd.worker->reset_cursor(d->ssd.worker);
|
||||
d->ssd.worker->reset_image_cache(d->ssd.worker);
|
||||
- qemu_mutex_lock_iothread();
|
||||
qxl_reset_surfaces(d);
|
||||
qxl_reset_memslots(d);
|
||||
|
||||
@@ -803,9 +801,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d)
|
||||
{
|
||||
dprint(d, 1, "%s:\n", __FUNCTION__);
|
||||
d->mode = QXL_MODE_UNDEFINED;
|
||||
- qemu_mutex_unlock_iothread();
|
||||
d->ssd.worker->destroy_surfaces(d->ssd.worker);
|
||||
- qemu_mutex_lock_iothread();
|
||||
memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds));
|
||||
}
|
||||
|
||||
@@ -874,9 +870,7 @@ static void qxl_destroy_primary(PCIQXLDevice *d)
|
||||
dprint(d, 1, "%s\n", __FUNCTION__);
|
||||
|
||||
d->mode = QXL_MODE_UNDEFINED;
|
||||
- qemu_mutex_unlock_iothread();
|
||||
d->ssd.worker->destroy_primary_surface(d->ssd.worker, 0);
|
||||
- qemu_mutex_lock_iothread();
|
||||
}
|
||||
|
||||
static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
|
||||
@@ -946,10 +940,8 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
case QXL_IO_UPDATE_AREA:
|
||||
{
|
||||
QXLRect update = d->ram->update_area;
|
||||
- qemu_mutex_unlock_iothread();
|
||||
d->ssd.worker->update_area(d->ssd.worker, d->ram->update_surface,
|
||||
&update, NULL, 0, 0);
|
||||
- qemu_mutex_lock_iothread();
|
||||
break;
|
||||
}
|
||||
case QXL_IO_NOTIFY_CMD:
|
||||
diff --git a/ui/spice-display.c b/ui/spice-display.c
|
||||
index bdd14b8..ecb22cc 100644
|
||||
--- a/ui/spice-display.c
|
||||
+++ b/ui/spice-display.c
|
||||
@@ -62,13 +62,7 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r)
|
||||
dest->right = MAX(dest->right, r->right);
|
||||
}
|
||||
|
||||
-/*
|
||||
- * Called from spice server thread context (via interface_get_command).
|
||||
- *
|
||||
- * We must aquire the global qemu mutex here to make sure the
|
||||
- * DisplayState (+DisplaySurface) we are accessing doesn't change
|
||||
- * underneath us.
|
||||
- */
|
||||
+/* Called from io-thread context (via pipe_read) */
|
||||
SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
|
||||
{
|
||||
SimpleSpiceUpdate *update;
|
||||
@@ -78,9 +72,7 @@ SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
|
||||
uint8_t *src, *dst;
|
||||
int by, bw, bh;
|
||||
|
||||
- qemu_mutex_lock_iothread();
|
||||
if (qemu_spice_rect_is_empty(&ssd->dirty)) {
|
||||
- qemu_mutex_unlock_iothread();
|
||||
return NULL;
|
||||
};
|
||||
|
||||
@@ -141,7 +133,6 @@ SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
|
||||
cmd->data = (intptr_t)drawable;
|
||||
|
||||
memset(&ssd->dirty, 0, sizeof(ssd->dirty));
|
||||
- qemu_mutex_unlock_iothread();
|
||||
return update;
|
||||
}
|
||||
|
||||
@@ -169,6 +160,7 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
|
||||
ssd->worker->add_memslot(ssd->worker, &memslot);
|
||||
}
|
||||
|
||||
+/* called from iothread (main) or a vcpu-thread */
|
||||
void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
|
||||
{
|
||||
QXLDevSurfaceCreate surface;
|
||||
@@ -186,18 +178,14 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
|
||||
surface.mem = (intptr_t)ssd->buf;
|
||||
surface.group_id = MEMSLOT_GROUP_HOST;
|
||||
|
||||
- qemu_mutex_unlock_iothread();
|
||||
ssd->worker->create_primary_surface(ssd->worker, 0, &surface);
|
||||
- qemu_mutex_lock_iothread();
|
||||
}
|
||||
|
||||
void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
|
||||
{
|
||||
dprint(1, "%s:\n", __FUNCTION__);
|
||||
|
||||
- qemu_mutex_unlock_iothread();
|
||||
ssd->worker->destroy_primary_surface(ssd->worker, 0);
|
||||
- qemu_mutex_lock_iothread();
|
||||
}
|
||||
|
||||
void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
|
||||
@@ -207,9 +195,7 @@ void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
|
||||
if (running) {
|
||||
ssd->worker->start(ssd->worker);
|
||||
} else {
|
||||
- qemu_mutex_unlock_iothread();
|
||||
ssd->worker->stop(ssd->worker);
|
||||
- qemu_mutex_lock_iothread();
|
||||
}
|
||||
ssd->running = running;
|
||||
}
|
||||
@@ -233,6 +219,7 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
|
||||
qemu_spice_rect_union(&ssd->dirty, &update_area);
|
||||
}
|
||||
|
||||
+/* called only from iothread (main) */
|
||||
void qemu_spice_display_resize(SimpleSpiceDisplay *ssd)
|
||||
{
|
||||
dprint(1, "%s:\n", __FUNCTION__);
|
||||
--
|
||||
1.7.3.2
|
||||
|
@ -1,249 +0,0 @@
|
||||
>From 1a33e5f2fa6de800047517a6f3251dc7191c97b5 Mon Sep 17 00:00:00 2001
|
||||
From: Alon Levy <alevy@redhat.com>
|
||||
Date: Wed, 16 Mar 2011 16:02:16 +0100
|
||||
Subject: [PATCH 4/4] hw/qxl-render: drop cursor locks, replace with pipe
|
||||
|
||||
Switching locking protection of ds->cursor_set/cursor_move to moving
|
||||
every call to these functions into the iothread and using the ssd->pipe
|
||||
to transfer that, adding QXL_SERVER_CURSOR_SET, QXL_SERVER_CURSOR_MOVE.
|
||||
|
||||
This is tested with both -vnc :0 -spice and -sdl -spice.
|
||||
---
|
||||
hw/qxl-render.c | 25 +++++++++-----
|
||||
hw/qxl.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
hw/qxl.h | 4 ++
|
||||
ui/spice-display.h | 13 +++++++-
|
||||
4 files changed, 122 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/hw/qxl-render.c b/hw/qxl-render.c
|
||||
index 58965e0..6759edb 100644
|
||||
--- a/hw/qxl-render.c
|
||||
+++ b/hw/qxl-render.c
|
||||
@@ -178,7 +178,6 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
-
|
||||
/* called from spice server thread context only */
|
||||
void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
|
||||
{
|
||||
@@ -209,18 +208,26 @@ void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
|
||||
if (c == NULL) {
|
||||
c = cursor_builtin_left_ptr();
|
||||
}
|
||||
- qemu_mutex_lock_iothread();
|
||||
- qxl->ssd.ds->cursor_define(c);
|
||||
- qxl->ssd.ds->mouse_set(x, y, 1);
|
||||
- qemu_mutex_unlock_iothread();
|
||||
- cursor_put(c);
|
||||
+ qxl_server_request_cursor_set(qxl, c, x, y);
|
||||
break;
|
||||
case QXL_CURSOR_MOVE:
|
||||
x = cmd->u.position.x;
|
||||
y = cmd->u.position.y;
|
||||
- qemu_mutex_lock_iothread();
|
||||
- qxl->ssd.ds->mouse_set(x, y, 1);
|
||||
- qemu_mutex_unlock_iothread();
|
||||
+ qxl_server_request_cursor_move(qxl, x, y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
+
|
||||
+/* called from iothread only (via qxl.c:pipe_read) */
|
||||
+void qxl_render_cursor_set(SimpleSpiceDisplay *ssd, QEMUCursor *c, int x, int y)
|
||||
+{
|
||||
+ ssd->ds->cursor_define(c);
|
||||
+ ssd->ds->mouse_set(x, y, 1);
|
||||
+ cursor_put(c);
|
||||
+}
|
||||
+
|
||||
+/* called from iothread only (via qxl.c:pipe_read) */
|
||||
+void qxl_render_cursor_move(SimpleSpiceDisplay *ssd, int x, int y)
|
||||
+{
|
||||
+ ssd->ds->mouse_set(x, y, 1);
|
||||
+}
|
||||
diff --git a/hw/qxl.c b/hw/qxl.c
|
||||
index cf3c938..4c27deb 100644
|
||||
--- a/hw/qxl.c
|
||||
+++ b/hw/qxl.c
|
||||
@@ -117,6 +117,27 @@ static QXLMode qxl_modes[] = {
|
||||
#endif
|
||||
};
|
||||
|
||||
+typedef struct __attribute__ ((__packed__)) {
|
||||
+ QEMUCursor *c;
|
||||
+ int x;
|
||||
+ int y;
|
||||
+} QXLServerCursorSet;
|
||||
+
|
||||
+typedef struct __attribute__ ((__packed__)) {
|
||||
+ int x;
|
||||
+ int y;
|
||||
+} QXLServerCursorMove;
|
||||
+
|
||||
+typedef struct __attribute__ ((__packed__)) {
|
||||
+ unsigned char req;
|
||||
+ QXLServerCursorMove data;
|
||||
+} QXLServerCursorMoveRequest;
|
||||
+
|
||||
+typedef struct __attribute__ ((__packed__)) {
|
||||
+ unsigned char req;
|
||||
+ QXLServerCursorSet data;
|
||||
+} QXLServerCursorSetRequest;
|
||||
+
|
||||
static PCIQXLDevice *qxl0;
|
||||
|
||||
static void qxl_send_events(PCIQXLDevice *d, uint32_t events);
|
||||
@@ -337,6 +358,33 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
|
||||
}
|
||||
|
||||
/* called from spice server thread context only */
|
||||
+void qxl_server_request_cursor_set(PCIQXLDevice *qxl, QEMUCursor *c, int x, int y)
|
||||
+{
|
||||
+ QXLServerCursorSetRequest req;
|
||||
+ int r;
|
||||
+
|
||||
+ req.req = QXL_SERVER_CURSOR_SET;
|
||||
+ req.data.c = c;
|
||||
+ req.data.x = x;
|
||||
+ req.data.y = y;
|
||||
+ r = write(qxl->ssd.pipe[1], &req, sizeof(req));
|
||||
+ assert(r == sizeof(req));
|
||||
+}
|
||||
+
|
||||
+/* called from spice server thread context only */
|
||||
+void qxl_server_request_cursor_move(PCIQXLDevice *qxl, int x, int y)
|
||||
+{
|
||||
+ QXLServerCursorMoveRequest req;
|
||||
+ int r;
|
||||
+
|
||||
+ req.req = QXL_SERVER_CURSOR_MOVE;
|
||||
+ req.data.x = x;
|
||||
+ req.data.y = y;
|
||||
+ r = write(qxl->ssd.pipe[1], &req, sizeof(req));
|
||||
+ assert(r == sizeof(req));
|
||||
+}
|
||||
+
|
||||
+/* called from spice server thread context only */
|
||||
static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
|
||||
{
|
||||
PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
|
||||
@@ -1055,12 +1103,37 @@ static void qxl_map(PCIDevice *pci, int region_num,
|
||||
}
|
||||
}
|
||||
|
||||
+static void read_bytes(int fd, void *buf, int len_requested)
|
||||
+{
|
||||
+ int len;
|
||||
+ int total_len = 0;
|
||||
+
|
||||
+ do {
|
||||
+ len = read(fd, buf, len_requested - total_len);
|
||||
+ if (len < 0) {
|
||||
+ if (errno == EINTR || errno == EAGAIN) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ perror("qxl: pipe_read: read failed");
|
||||
+ /* will abort once it's out of the while loop */
|
||||
+ break;
|
||||
+ }
|
||||
+ total_len += len;
|
||||
+ buf = (uint8_t *)buf + len;
|
||||
+ } while (total_len < len_requested);
|
||||
+ assert(total_len == len_requested);
|
||||
+}
|
||||
+
|
||||
static void pipe_read(void *opaque)
|
||||
{
|
||||
SimpleSpiceDisplay *ssd = opaque;
|
||||
unsigned char cmd;
|
||||
int len, set_irq = 0;
|
||||
int create_update = 0;
|
||||
+ int cursor_set = 0;
|
||||
+ int cursor_move = 0;
|
||||
+ QXLServerCursorSet cursor_set_data;
|
||||
+ QXLServerCursorMove cursor_move_data;
|
||||
|
||||
while (1) {
|
||||
cmd = 0;
|
||||
@@ -1082,6 +1155,17 @@ static void pipe_read(void *opaque)
|
||||
case QXL_SERVER_CREATE_UPDATE:
|
||||
create_update = 1;
|
||||
break;
|
||||
+ case QXL_SERVER_CURSOR_SET:
|
||||
+ if (cursor_set == 1) {
|
||||
+ cursor_put(cursor_set_data.c);
|
||||
+ }
|
||||
+ cursor_set = 1;
|
||||
+ read_bytes(ssd->pipe[0], &cursor_set_data, sizeof(cursor_set_data));
|
||||
+ break;
|
||||
+ case QXL_SERVER_CURSOR_MOVE:
|
||||
+ cursor_move = 1;
|
||||
+ read_bytes(ssd->pipe[0], &cursor_move_data, sizeof(cursor_move_data));
|
||||
+ break;
|
||||
default:
|
||||
fprintf(stderr, "%s: unknown cmd %u\n", __FUNCTION__, cmd);
|
||||
abort();
|
||||
@@ -1099,6 +1183,12 @@ static void pipe_read(void *opaque)
|
||||
if (set_irq) {
|
||||
qxl_set_irq(container_of(ssd, PCIQXLDevice, ssd));
|
||||
}
|
||||
+ if (cursor_move) {
|
||||
+ qxl_render_cursor_move(ssd, cursor_move_data.x, cursor_move_data.y);
|
||||
+ }
|
||||
+ if (cursor_set) {
|
||||
+ qxl_render_cursor_set(ssd, cursor_set_data.c, cursor_set_data.x, cursor_set_data.y);
|
||||
+ }
|
||||
}
|
||||
|
||||
static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
|
||||
diff --git a/hw/qxl.h b/hw/qxl.h
|
||||
index 701245f..f4f99ec 100644
|
||||
--- a/hw/qxl.h
|
||||
+++ b/hw/qxl.h
|
||||
@@ -93,6 +93,8 @@ typedef struct PCIQXLDevice {
|
||||
|
||||
/* qxl.c */
|
||||
void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
|
||||
+void qxl_server_request_cursor_set(PCIQXLDevice *qxl, QEMUCursor *c, int x, int y);
|
||||
+void qxl_server_request_cursor_move(PCIQXLDevice *qxl, int x, int y);
|
||||
|
||||
/* qxl-logger.c */
|
||||
void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id);
|
||||
@@ -102,3 +104,5 @@ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext);
|
||||
void qxl_render_resize(PCIQXLDevice *qxl);
|
||||
void qxl_render_update(PCIQXLDevice *qxl);
|
||||
void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext);
|
||||
+void qxl_render_cursor_set(SimpleSpiceDisplay *ssd, QEMUCursor *c, int x, int y);
|
||||
+void qxl_render_cursor_move(SimpleSpiceDisplay *ssd, int x, int y);
|
||||
diff --git a/ui/spice-display.h b/ui/spice-display.h
|
||||
index 2be6a34..bbfd689 100644
|
||||
--- a/ui/spice-display.h
|
||||
+++ b/ui/spice-display.h
|
||||
@@ -31,11 +31,22 @@
|
||||
|
||||
#define NUM_SURFACES 1024
|
||||
|
||||
-/* For commands/requests from server thread to iothread */
|
||||
+/*
|
||||
+ * Commands/requests from server thread to iothread.
|
||||
+ * Note that CREATE_UPDATE is used both with qxl and without it (spice-display)
|
||||
+ * the others are only used with the qxl device.
|
||||
+ *
|
||||
+ * SET_IRQ - just the request is sent (1 byte)
|
||||
+ * CREATE_UPDATE - jus the request is sent (1 byte)
|
||||
+ * CURSOR_SET - send QXLServerRequestCursorSet
|
||||
+ * CURSOR_MOVE - send QXLServerRequestCursorMove
|
||||
+ */
|
||||
#define QXL_EMPTY_UPDATE ((void *)-1)
|
||||
enum {
|
||||
QXL_SERVER_SET_IRQ = 1,
|
||||
QXL_SERVER_CREATE_UPDATE,
|
||||
+ QXL_SERVER_CURSOR_SET,
|
||||
+ QXL_SERVER_CURSOR_MOVE
|
||||
};
|
||||
|
||||
struct SimpleSpiceUpdate;
|
||||
--
|
||||
1.7.3.2
|
||||
|
@ -1,56 +0,0 @@
|
||||
>From b248befcd93bcd713971b15147fcaa217a3d1bb7 Mon Sep 17 00:00:00 2001
|
||||
From: Amit Shah <amit.shah@redhat.com>
|
||||
Date: Mon, 21 Mar 2011 21:57:47 +0100
|
||||
Subject: [PATCH 05/17] char: Split out tcp socket close code in a separate function
|
||||
|
||||
Signed-off-by: Amit Shah <amit.shah@redhat.com>
|
||||
---
|
||||
qemu-char.c | 25 ++++++++++++++++---------
|
||||
1 files changed, 16 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/qemu-char.c b/qemu-char.c
|
||||
index bd4e944..4b57af9 100644
|
||||
--- a/qemu-char.c
|
||||
+++ b/qemu-char.c
|
||||
@@ -1911,6 +1911,21 @@ typedef struct {
|
||||
|
||||
static void tcp_chr_accept(void *opaque);
|
||||
|
||||
+static void tcp_closed(void *opaque)
|
||||
+{
|
||||
+ CharDriverState *chr = opaque;
|
||||
+ TCPCharDriver *s = chr->opaque;
|
||||
+
|
||||
+ s->connected = 0;
|
||||
+ if (s->listen_fd >= 0) {
|
||||
+ qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
|
||||
+ }
|
||||
+ qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
|
||||
+ closesocket(s->fd);
|
||||
+ s->fd = -1;
|
||||
+ qemu_chr_event(chr, CHR_EVENT_CLOSED);
|
||||
+}
|
||||
+
|
||||
static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
|
||||
{
|
||||
TCPCharDriver *s = chr->opaque;
|
||||
@@ -2061,15 +2076,7 @@ static void tcp_chr_read(void *opaque)
|
||||
len = s->max_size;
|
||||
size = tcp_chr_recv(chr, (void *)buf, len);
|
||||
if (size == 0) {
|
||||
- /* connection closed */
|
||||
- s->connected = 0;
|
||||
- if (s->listen_fd >= 0) {
|
||||
- qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
|
||||
- }
|
||||
- qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
|
||||
- closesocket(s->fd);
|
||||
- s->fd = -1;
|
||||
- qemu_chr_event(chr, CHR_EVENT_CLOSED);
|
||||
+ tcp_closed(chr);
|
||||
} else if (size > 0) {
|
||||
if (s->do_telnetopt)
|
||||
tcp_chr_process_IAC_bytes(chr, s, buf, &size);
|
||||
--
|
||||
1.7.3.2
|
||||
|
@ -1,673 +0,0 @@
|
||||
>From 003cc09f8fc34e7571ebd4a89ea6aa6324a80b54 Mon Sep 17 00:00:00 2001
|
||||
From: Amit Shah <amit.shah@redhat.com>
|
||||
Date: Mon, 21 Mar 2011 20:31:45 +0100
|
||||
Subject: [PATCH 06/19] char: Add a QemuChrHandlers struct to initialise chardev handlers
|
||||
|
||||
Instead of passing each handler in the qemu_add_handlers() function,
|
||||
create a struct of handlers that can be passed to the function instead.
|
||||
|
||||
Signed-off-by: Amit Shah <amit.shah@redhat.com>
|
||||
---
|
||||
gdbstub.c | 9 +++++++--
|
||||
hw/debugcon.c | 2 +-
|
||||
hw/escc.c | 9 +++++++--
|
||||
hw/etraxfs_ser.c | 13 +++++++++----
|
||||
hw/grlib_apbuart.c | 12 +++++++-----
|
||||
hw/ivshmem.c | 28 ++++++++++++++++++++++------
|
||||
hw/mcf_uart.c | 9 +++++++--
|
||||
hw/pl011.c | 9 +++++++--
|
||||
hw/pxa2xx.c | 13 +++++++++----
|
||||
hw/serial.c | 9 +++++++--
|
||||
hw/sh_serial.c | 12 +++++++++---
|
||||
hw/syborg_serial.c | 9 +++++++--
|
||||
hw/usb-serial.c | 9 +++++++--
|
||||
hw/virtio-console.c | 9 +++++++--
|
||||
hw/xen_console.c | 16 +++++++++++-----
|
||||
hw/xilinx_uartlite.c | 11 +++++++++--
|
||||
monitor.c | 18 ++++++++++++++----
|
||||
net/slirp.c | 8 ++++++--
|
||||
qemu-char.c | 30 +++++++++++++++++++++---------
|
||||
qemu-char.h | 13 +++++++++----
|
||||
20 files changed, 183 insertions(+), 65 deletions(-)
|
||||
|
||||
diff --git a/gdbstub.c b/gdbstub.c
|
||||
index 14e8b9b..4190ac7 100644
|
||||
--- a/gdbstub.c
|
||||
+++ b/gdbstub.c
|
||||
@@ -2634,6 +2634,12 @@ static void gdb_sigterm_handler(int signal)
|
||||
}
|
||||
#endif
|
||||
|
||||
+static const QemuChrHandlers gdb_handlers = {
|
||||
+ .fd_can_read = gdb_chr_can_receive,
|
||||
+ .fd_read = gdb_chr_receive,
|
||||
+ .fd_event = gdb_chr_event,
|
||||
+};
|
||||
+
|
||||
int gdbserver_start(const char *device)
|
||||
{
|
||||
GDBState *s;
|
||||
@@ -2663,8 +2669,7 @@ int gdbserver_start(const char *device)
|
||||
if (!chr)
|
||||
return -1;
|
||||
|
||||
- qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive,
|
||||
- gdb_chr_event, NULL);
|
||||
+ qemu_chr_add_handlers(chr, &gdb_handlers, NULL);
|
||||
}
|
||||
|
||||
s = gdbserver_state;
|
||||
diff --git a/hw/debugcon.c b/hw/debugcon.c
|
||||
index 5ee6821..e79a595 100644
|
||||
--- a/hw/debugcon.c
|
||||
+++ b/hw/debugcon.c
|
||||
@@ -73,7 +73,7 @@ static void debugcon_init_core(DebugconState *s)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
- qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, s);
|
||||
+ qemu_chr_add_handlers(s->chr, NULL, s);
|
||||
}
|
||||
|
||||
static int debugcon_isa_initfn(ISADevice *dev)
|
||||
diff --git a/hw/escc.c b/hw/escc.c
|
||||
index f6fd919..dfa329a 100644
|
||||
--- a/hw/escc.c
|
||||
+++ b/hw/escc.c
|
||||
@@ -898,6 +898,12 @@ void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq,
|
||||
sysbus_mmio_map(s, 0, base);
|
||||
}
|
||||
|
||||
+static const QemuChrHandlers serial_handlers = {
|
||||
+ .fd_can_read = serial_can_receive,
|
||||
+ .fd_read = serial_receive1,
|
||||
+ .fd_event = serial_event,
|
||||
+};
|
||||
+
|
||||
static int escc_init1(SysBusDevice *dev)
|
||||
{
|
||||
SerialState *s = FROM_SYSBUS(SerialState, dev);
|
||||
@@ -911,8 +917,7 @@ static int escc_init1(SysBusDevice *dev)
|
||||
s->chn[i].chn = 1 - i;
|
||||
s->chn[i].clock = s->frequency / 2;
|
||||
if (s->chn[i].chr) {
|
||||
- qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive,
|
||||
- serial_receive1, serial_event, &s->chn[i]);
|
||||
+ qemu_chr_add_handlers(s->chn[i].chr, &serial_handlers, &s->chn[i]);
|
||||
}
|
||||
}
|
||||
s->chn[0].otherchn = &s->chn[1];
|
||||
diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c
|
||||
index 2787ebd..406121c 100644
|
||||
--- a/hw/etraxfs_ser.c
|
||||
+++ b/hw/etraxfs_ser.c
|
||||
@@ -190,6 +190,12 @@ static void serial_event(void *opaque, int event)
|
||||
|
||||
}
|
||||
|
||||
+static const QemuChrHandlers serial_handlers = {
|
||||
+ .fd_can_read = serial_can_receive,
|
||||
+ .fd_read = serial_receive,
|
||||
+ .fd_event = serial_event,
|
||||
+};
|
||||
+
|
||||
static int etraxfs_ser_init(SysBusDevice *dev)
|
||||
{
|
||||
struct etrax_serial *s = FROM_SYSBUS(typeof (*s), dev);
|
||||
@@ -204,10 +210,9 @@ static int etraxfs_ser_init(SysBusDevice *dev)
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
sysbus_init_mmio(dev, R_MAX * 4, ser_regs);
|
||||
s->chr = qdev_init_chardev(&dev->qdev);
|
||||
- if (s->chr)
|
||||
- qemu_chr_add_handlers(s->chr,
|
||||
- serial_can_receive, serial_receive,
|
||||
- serial_event, s);
|
||||
+ if (s->chr) {
|
||||
+ qemu_chr_add_handlers(s->chr, &serial_handlers, s);
|
||||
+ }
|
||||
return 0;
|
||||
}
|
||||
|
||||
diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c
|
||||
index 101b150..40d6968 100644
|
||||
--- a/hw/grlib_apbuart.c
|
||||
+++ b/hw/grlib_apbuart.c
|
||||
@@ -144,16 +144,18 @@ static CPUWriteMemoryFunc * const grlib_apbuart_write[] = {
|
||||
NULL, NULL, grlib_apbuart_writel,
|
||||
};
|
||||
|
||||
+static const QemuChrHandlers grlib_handlers = {
|
||||
+ .fd_can_read = grlib_apbuart_can_receive,
|
||||
+ .fd_read = grlib_apbuart_receive,
|
||||
+ .fd_event = grlib_apbuart_event,
|
||||
+};
|
||||
+
|
||||
static int grlib_apbuart_init(SysBusDevice *dev)
|
||||
{
|
||||
UART *uart = FROM_SYSBUS(typeof(*uart), dev);
|
||||
int uart_regs = 0;
|
||||
|
||||
- qemu_chr_add_handlers(uart->chr,
|
||||
- grlib_apbuart_can_receive,
|
||||
- grlib_apbuart_receive,
|
||||
- grlib_apbuart_event,
|
||||
- uart);
|
||||
+ qemu_chr_add_handlers(uart->chr, &grlib_handlers, uart);
|
||||
|
||||
sysbus_init_irq(dev, &uart->irq);
|
||||
|
||||
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
|
||||
index 7b19a81..ef8e5ce 100644
|
||||
--- a/hw/ivshmem.c
|
||||
+++ b/hw/ivshmem.c
|
||||
@@ -312,6 +312,18 @@ static void fake_irqfd(void *opaque, const uint8_t *buf, int size) {
|
||||
msix_notify(pdev, entry->vector);
|
||||
}
|
||||
|
||||
+static const QemuChrHandlers ivshmem_handlers = {
|
||||
+ .fd_can_read = ivshmem_can_receive,
|
||||
+ .fd_read = ivshmem_receive,
|
||||
+ .fd_event = ivshmem_event,
|
||||
+};
|
||||
+
|
||||
+static const QemuChrHandlers ivshmem_msi_handlers = {
|
||||
+ .fd_can_read = ivshmem_can_receive,
|
||||
+ .fd_read = fake_irqfd,
|
||||
+ .fd_event = ivshmem_event,
|
||||
+};
|
||||
+
|
||||
static CharDriverState* create_eventfd_chr_device(void * opaque, int eventfd,
|
||||
int vector)
|
||||
{
|
||||
@@ -331,11 +343,10 @@ static CharDriverState* create_eventfd_chr_device(void * opaque, int eventfd,
|
||||
s->eventfd_table[vector].pdev = &s->dev;
|
||||
s->eventfd_table[vector].vector = vector;
|
||||
|
||||
- qemu_chr_add_handlers(chr, ivshmem_can_receive, fake_irqfd,
|
||||
- ivshmem_event, &s->eventfd_table[vector]);
|
||||
+ qemu_chr_add_handlers(chr, &ivshmem_msi_handlers,
|
||||
+ &s->eventfd_table[vector]);
|
||||
} else {
|
||||
- qemu_chr_add_handlers(chr, ivshmem_can_receive, ivshmem_receive,
|
||||
- ivshmem_event, s);
|
||||
+ qemu_chr_add_handlers(chr, &ivshmem_handlers, s);
|
||||
}
|
||||
|
||||
return chr;
|
||||
@@ -666,6 +677,12 @@ static int ivshmem_load(QEMUFile* f, void *opaque, int version_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static const QemuChrHandlers ivshmem_server_handlers = {
|
||||
+ .fd_can_read = ivshmem_can_receive,
|
||||
+ .fd_read = ivshmem_read,
|
||||
+ .fd_event = ivshmem_event,
|
||||
+};
|
||||
+
|
||||
static int pci_ivshmem_init(PCIDevice *dev)
|
||||
{
|
||||
IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
|
||||
@@ -754,8 +771,7 @@ static int pci_ivshmem_init(PCIDevice *dev)
|
||||
|
||||
s->eventfd_chr = qemu_mallocz(s->vectors * sizeof(CharDriverState *));
|
||||
|
||||
- qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read,
|
||||
- ivshmem_event, s);
|
||||
+ qemu_chr_add_handlers(s->server_chr, &ivshmem_server_handlers, s);
|
||||
} else {
|
||||
/* just map the file immediately, we're not using a server */
|
||||
int fd;
|
||||
diff --git a/hw/mcf_uart.c b/hw/mcf_uart.c
|
||||
index db57096..9928c11 100644
|
||||
--- a/hw/mcf_uart.c
|
||||
+++ b/hw/mcf_uart.c
|
||||
@@ -268,6 +268,12 @@ static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size)
|
||||
mcf_uart_push_byte(s, buf[0]);
|
||||
}
|
||||
|
||||
+static const QemuChrHandlers mcf_uart_handlers = {
|
||||
+ .fd_can_read = mcf_uart_can_receive,
|
||||
+ .fd_read = mcf_uart_receive,
|
||||
+ .fd_event = mcf_uart_event,
|
||||
+};
|
||||
+
|
||||
void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
|
||||
{
|
||||
mcf_uart_state *s;
|
||||
@@ -276,8 +282,7 @@ void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
|
||||
s->chr = chr;
|
||||
s->irq = irq;
|
||||
if (chr) {
|
||||
- qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive,
|
||||
- mcf_uart_event, s);
|
||||
+ qemu_chr_add_handlers(chr, &mcf_uart_handlers, s);
|
||||
}
|
||||
mcf_uart_reset(s);
|
||||
return s;
|
||||
diff --git a/hw/pl011.c b/hw/pl011.c
|
||||
index 77f0dbf..d93c655 100644
|
||||
--- a/hw/pl011.c
|
||||
+++ b/hw/pl011.c
|
||||
@@ -286,6 +286,12 @@ static int pl011_load(QEMUFile *f, void *opaque, int version_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static const QemuChrHandlers pl011_handlers = {
|
||||
+ .fd_can_read = pl011_can_receive,
|
||||
+ .fd_read = pl011_receive,
|
||||
+ .fd_event = pl011_event,
|
||||
+};
|
||||
+
|
||||
static int pl011_init(SysBusDevice *dev, const unsigned char *id)
|
||||
{
|
||||
int iomemtype;
|
||||
@@ -304,8 +310,7 @@ static int pl011_init(SysBusDevice *dev, const unsigned char *id)
|
||||
s->cr = 0x300;
|
||||
s->flags = 0x90;
|
||||
if (s->chr) {
|
||||
- qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive,
|
||||
- pl011_event, s);
|
||||
+ qemu_chr_add_handlers(s->chr, &pl011_handlers, s);
|
||||
}
|
||||
register_savevm(&dev->qdev, "pl011_uart", -1, 1, pl011_save, pl011_load, s);
|
||||
return 0;
|
||||
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
|
||||
index d966846..d7ebf33 100644
|
||||
--- a/hw/pxa2xx.c
|
||||
+++ b/hw/pxa2xx.c
|
||||
@@ -1995,6 +1995,12 @@ static int pxa2xx_fir_load(QEMUFile *f, void *opaque, int version_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static const QemuChrHandlers pxa2xx_handlers = {
|
||||
+ .fd_can_read = pxa2xx_fir_is_empty,
|
||||
+ .fd_read = pxa2xx_fir_rx,
|
||||
+ .fd_event = pxa2xx_fir_event,
|
||||
+};
|
||||
+
|
||||
static PXA2xxFIrState *pxa2xx_fir_init(target_phys_addr_t base,
|
||||
qemu_irq irq, PXA2xxDMAState *dma,
|
||||
CharDriverState *chr)
|
||||
@@ -2013,10 +2019,9 @@ static PXA2xxFIrState *pxa2xx_fir_init(target_phys_addr_t base,
|
||||
pxa2xx_fir_writefn, s, DEVICE_NATIVE_ENDIAN);
|
||||
cpu_register_physical_memory(base, 0x1000, iomemtype);
|
||||
|
||||
- if (chr)
|
||||
- qemu_chr_add_handlers(chr, pxa2xx_fir_is_empty,
|
||||
- pxa2xx_fir_rx, pxa2xx_fir_event, s);
|
||||
-
|
||||
+ if (chr) {
|
||||
+ qemu_chr_add_handlers(chr, &pxa2xx_handlers, s);
|
||||
+ }
|
||||
register_savevm(NULL, "pxa2xx_fir", 0, 0, pxa2xx_fir_save,
|
||||
pxa2xx_fir_load, s);
|
||||
|
||||
diff --git a/hw/serial.c b/hw/serial.c
|
||||
index 2c4af61..65265e2 100644
|
||||
--- a/hw/serial.c
|
||||
+++ b/hw/serial.c
|
||||
@@ -727,6 +727,12 @@ static void serial_reset(void *opaque)
|
||||
qemu_irq_lower(s->irq);
|
||||
}
|
||||
|
||||
+static const QemuChrHandlers serial_handlers = {
|
||||
+ .fd_can_read = serial_can_receive1,
|
||||
+ .fd_read = serial_receive1,
|
||||
+ .fd_event = serial_event,
|
||||
+};
|
||||
+
|
||||
static void serial_init_core(SerialState *s)
|
||||
{
|
||||
if (!s->chr) {
|
||||
@@ -741,8 +747,7 @@ static void serial_init_core(SerialState *s)
|
||||
|
||||
qemu_register_reset(serial_reset, s);
|
||||
|
||||
- qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1,
|
||||
- serial_event, s);
|
||||
+ qemu_chr_add_handlers(s->chr, &serial_handlers, s);
|
||||
}
|
||||
|
||||
/* Change the main reference oscillator frequency. */
|
||||
diff --git a/hw/sh_serial.c b/hw/sh_serial.c
|
||||
index 191f4a6..8b6460d 100644
|
||||
--- a/hw/sh_serial.c
|
||||
+++ b/hw/sh_serial.c
|
||||
@@ -350,6 +350,12 @@ static CPUWriteMemoryFunc * const sh_serial_writefn[] = {
|
||||
&sh_serial_write,
|
||||
};
|
||||
|
||||
+static const QemuChrHandlers sh_serial_handlers = {
|
||||
+ .fd_can_read = sh_serial_can_receive1,
|
||||
+ .fd_read = sh_serial_receive1,
|
||||
+ .fd_event = sh_serial_event,
|
||||
+};
|
||||
+
|
||||
void sh_serial_init (target_phys_addr_t base, int feat,
|
||||
uint32_t freq, CharDriverState *chr,
|
||||
qemu_irq eri_source,
|
||||
@@ -389,9 +395,9 @@ void sh_serial_init (target_phys_addr_t base, int feat,
|
||||
|
||||
s->chr = chr;
|
||||
|
||||
- if (chr)
|
||||
- qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1,
|
||||
- sh_serial_event, s);
|
||||
+ if (chr) {
|
||||
+ qemu_chr_add_handlers(chr, &sh_serial_handlers, s);
|
||||
+ }
|
||||
|
||||
s->eri = eri_source;
|
||||
s->rxi = rxi_source;
|
||||
diff --git a/hw/syborg_serial.c b/hw/syborg_serial.c
|
||||
index 34ce076..124b636 100644
|
||||
--- a/hw/syborg_serial.c
|
||||
+++ b/hw/syborg_serial.c
|
||||
@@ -315,6 +315,12 @@ static int syborg_serial_load(QEMUFile *f, void *opaque, int version_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static const QemuChrHandlers syborg_serial_handlers = {
|
||||
+ .fd_can_read = syborg_serial_can_receive,
|
||||
+ .fd_read = syborg_serial_receive,
|
||||
+ .fd_event = syborg_serial_event,
|
||||
+};
|
||||
+
|
||||
static int syborg_serial_init(SysBusDevice *dev)
|
||||
{
|
||||
SyborgSerialState *s = FROM_SYSBUS(SyborgSerialState, dev);
|
||||
@@ -327,8 +333,7 @@ static int syborg_serial_init(SysBusDevice *dev)
|
||||
sysbus_init_mmio(dev, 0x1000, iomemtype);
|
||||
s->chr = qdev_init_chardev(&dev->qdev);
|
||||
if (s->chr) {
|
||||
- qemu_chr_add_handlers(s->chr, syborg_serial_can_receive,
|
||||
- syborg_serial_receive, syborg_serial_event, s);
|
||||
+ qemu_chr_add_handlers(s->chr, &syborg_serial_handlers, s);
|
||||
}
|
||||
if (s->fifo_size <= 0) {
|
||||
fprintf(stderr, "syborg_serial: fifo too small\n");
|
||||
diff --git a/hw/usb-serial.c b/hw/usb-serial.c
|
||||
index 6763d52..2435d9d 100644
|
||||
--- a/hw/usb-serial.c
|
||||
+++ b/hw/usb-serial.c
|
||||
@@ -475,6 +475,12 @@ static void usb_serial_event(void *opaque, int event)
|
||||
}
|
||||
}
|
||||
|
||||
+static const QemuChrHandlers usb_serial_handlers = {
|
||||
+ .fd_can_read = usb_serial_can_read,
|
||||
+ .fd_read = usb_serial_read,
|
||||
+ .fd_event = usb_serial_event,
|
||||
+};
|
||||
+
|
||||
static int usb_serial_initfn(USBDevice *dev)
|
||||
{
|
||||
USBSerialState *s = DO_UPCAST(USBSerialState, dev, dev);
|
||||
@@ -486,8 +492,7 @@ static int usb_serial_initfn(USBDevice *dev)
|
||||
return -1;
|
||||
}
|
||||
|
||||
- qemu_chr_add_handlers(s->cs, usb_serial_can_read, usb_serial_read,
|
||||
- usb_serial_event, s);
|
||||
+ qemu_chr_add_handlers(s->cs, &usb_serial_handlers, s);
|
||||
usb_serial_handle_reset(dev);
|
||||
return 0;
|
||||
}
|
||||
diff --git a/hw/virtio-console.c b/hw/virtio-console.c
|
||||
index 62624ec..22cf28c 100644
|
||||
--- a/hw/virtio-console.c
|
||||
+++ b/hw/virtio-console.c
|
||||
@@ -57,13 +57,18 @@ static void chr_event(void *opaque, int event)
|
||||
}
|
||||
}
|
||||
|
||||
+static const QemuChrHandlers chr_handlers = {
|
||||
+ .fd_can_read = chr_can_read,
|
||||
+ .fd_read = chr_read,
|
||||
+ .fd_event = chr_event,
|
||||
+};
|
||||
+
|
||||
static int generic_port_init(VirtConsole *vcon, VirtIOSerialDevice *dev)
|
||||
{
|
||||
vcon->port.info = dev->info;
|
||||
|
||||
if (vcon->chr) {
|
||||
- qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
|
||||
- vcon);
|
||||
+ qemu_chr_add_handlers(vcon->chr, &chr_handlers, vcon);
|
||||
vcon->port.info->have_data = flush_buf;
|
||||
}
|
||||
return 0;
|
||||
diff --git a/hw/xen_console.c b/hw/xen_console.c
|
||||
index d2261f4..8327e4e 100644
|
||||
--- a/hw/xen_console.c
|
||||
+++ b/hw/xen_console.c
|
||||
@@ -202,6 +202,11 @@ static int con_init(struct XenDevice *xendev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static const QemuChrHandlers xencons_handlers = {
|
||||
+ .fd_can_read = xencons_can_receive,
|
||||
+ .fd_read = xencons_receive,
|
||||
+};
|
||||
+
|
||||
static int con_connect(struct XenDevice *xendev)
|
||||
{
|
||||
struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
|
||||
@@ -222,9 +227,9 @@ static int con_connect(struct XenDevice *xendev)
|
||||
return -1;
|
||||
|
||||
xen_be_bind_evtchn(&con->xendev);
|
||||
- if (con->chr)
|
||||
- qemu_chr_add_handlers(con->chr, xencons_can_receive, xencons_receive,
|
||||
- NULL, con);
|
||||
+ if (con->chr) {
|
||||
+ qemu_chr_add_handlers(con->chr, &xencons_handlers, con);
|
||||
+ }
|
||||
|
||||
xen_be_printf(xendev, 1, "ring mfn %d, remote port %d, local port %d, limit %zd\n",
|
||||
con->ring_ref,
|
||||
@@ -238,8 +243,9 @@ static void con_disconnect(struct XenDevice *xendev)
|
||||
{
|
||||
struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
|
||||
|
||||
- if (con->chr)
|
||||
- qemu_chr_add_handlers(con->chr, NULL, NULL, NULL, NULL);
|
||||
+ if (con->chr) {
|
||||
+ qemu_chr_add_handlers(con->chr, NULL, NULL);
|
||||
+ }
|
||||
xen_be_unbind_evtchn(&con->xendev);
|
||||
|
||||
if (con->sring) {
|
||||
diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c
|
||||
index 9b94e98..1845577 100644
|
||||
--- a/hw/xilinx_uartlite.c
|
||||
+++ b/hw/xilinx_uartlite.c
|
||||
@@ -193,6 +193,12 @@ static void uart_event(void *opaque, int event)
|
||||
|
||||
}
|
||||
|
||||
+static const QemuChrHandlers uart_handlers = {
|
||||
+ .fd_can_read = uart_can_rx,
|
||||
+ .fd_read = uart_rx,
|
||||
+ .fd_event = uart_event,
|
||||
+};
|
||||
+
|
||||
static int xilinx_uartlite_init(SysBusDevice *dev)
|
||||
{
|
||||
struct xlx_uartlite *s = FROM_SYSBUS(typeof (*s), dev);
|
||||
@@ -206,8 +212,9 @@ static int xilinx_uartlite_init(SysBusDevice *dev)
|
||||
sysbus_init_mmio(dev, R_MAX * 4, uart_regs);
|
||||
|
||||
s->chr = qdev_init_chardev(&dev->qdev);
|
||||
- if (s->chr)
|
||||
- qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
|
||||
+ if (s->chr) {
|
||||
+ qemu_chr_add_handlers(s->chr, &uart_handlers, s);
|
||||
+ }
|
||||
return 0;
|
||||
}
|
||||
|
||||
diff --git a/monitor.c b/monitor.c
|
||||
index 096d42b..a00a233 100644
|
||||
--- a/monitor.c
|
||||
+++ b/monitor.c
|
||||
@@ -5179,6 +5179,18 @@ static void monitor_event(void *opaque, int event)
|
||||
* End:
|
||||
*/
|
||||
|
||||
+static const QemuChrHandlers monitor_handlers = {
|
||||
+ .fd_can_read = monitor_can_read,
|
||||
+ .fd_read = monitor_read,
|
||||
+ .fd_event = monitor_event,
|
||||
+};
|
||||
+
|
||||
+static const QemuChrHandlers monitor_control_handlers = {
|
||||
+ .fd_can_read = monitor_can_read,
|
||||
+ .fd_read = monitor_control_read,
|
||||
+ .fd_event = monitor_control_event,
|
||||
+};
|
||||
+
|
||||
void monitor_init(CharDriverState *chr, int flags)
|
||||
{
|
||||
static int is_first_init = 1;
|
||||
@@ -5201,12 +5213,10 @@ void monitor_init(CharDriverState *chr, int flags)
|
||||
if (monitor_ctrl_mode(mon)) {
|
||||
mon->mc = qemu_mallocz(sizeof(MonitorControl));
|
||||
/* Control mode requires special handlers */
|
||||
- qemu_chr_add_handlers(chr, monitor_can_read, monitor_control_read,
|
||||
- monitor_control_event, mon);
|
||||
+ qemu_chr_add_handlers(chr, &monitor_control_handlers, mon);
|
||||
qemu_chr_set_echo(chr, true);
|
||||
} else {
|
||||
- qemu_chr_add_handlers(chr, monitor_can_read, monitor_read,
|
||||
- monitor_event, mon);
|
||||
+ qemu_chr_add_handlers(chr, &monitor_handlers, mon);
|
||||
}
|
||||
|
||||
QLIST_INSERT_HEAD(&mon_list, mon, entry);
|
||||
diff --git a/net/slirp.c b/net/slirp.c
|
||||
index b41c60a..437be46 100644
|
||||
--- a/net/slirp.c
|
||||
+++ b/net/slirp.c
|
||||
@@ -577,6 +577,11 @@ static void guestfwd_read(void *opaque, const uint8_t *buf, int size)
|
||||
slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size);
|
||||
}
|
||||
|
||||
+static const QemuChrHandlers guestfwd_handlers = {
|
||||
+ .fd_can_read = guestfwd_can_read,
|
||||
+ .fd_read = guestfwd_read,
|
||||
+};
|
||||
+
|
||||
static int slirp_guestfwd(SlirpState *s, const char *config_str,
|
||||
int legacy_format)
|
||||
{
|
||||
@@ -633,8 +638,7 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str,
|
||||
fwd->port = port;
|
||||
fwd->slirp = s->slirp;
|
||||
|
||||
- qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read,
|
||||
- NULL, fwd);
|
||||
+ qemu_chr_add_handlers(fwd->hd, &guestfwd_handlers, fwd);
|
||||
return 0;
|
||||
|
||||
fail_syntax:
|
||||
diff --git a/qemu-char.c b/qemu-char.c
|
||||
index 4b57af9..3a31d8b 100644
|
||||
--- a/qemu-char.c
|
||||
+++ b/qemu-char.c
|
||||
@@ -191,15 +191,22 @@ void qemu_chr_send_event(CharDriverState *s, int event)
|
||||
s->chr_send_event(s, event);
|
||||
}
|
||||
|
||||
+static const QemuChrHandlers null_handlers = {
|
||||
+ /* All handlers are initialised to NULL */
|
||||
+};
|
||||
+
|
||||
void qemu_chr_add_handlers(CharDriverState *s,
|
||||
- IOCanReadHandler *fd_can_read,
|
||||
- IOReadHandler *fd_read,
|
||||
- IOEventHandler *fd_event,
|
||||
- void *opaque)
|
||||
-{
|
||||
- s->chr_can_read = fd_can_read;
|
||||
- s->chr_read = fd_read;
|
||||
- s->chr_event = fd_event;
|
||||
+ const QemuChrHandlers *handlers, void *opaque)
|
||||
+{
|
||||
+ if (!s) {
|
||||
+ return;
|
||||
+ }
|
||||
+ if (!handlers) {
|
||||
+ handlers = &null_handlers;
|
||||
+ }
|
||||
+ s->chr_can_read = handlers->fd_can_read;
|
||||
+ s->chr_read = handlers->fd_read;
|
||||
+ s->chr_event = handlers->fd_event;
|
||||
s->handler_opaque = opaque;
|
||||
if (s->chr_update_read_handler)
|
||||
s->chr_update_read_handler(s);
|
||||
@@ -437,6 +444,12 @@ static void mux_chr_event(void *opaque, int event)
|
||||
mux_chr_send_event(d, i, event);
|
||||
}
|
||||
|
||||
+static const QemuChrHandlers mux_chr_handlers = {
|
||||
+ .fd_can_read = mux_chr_can_read,
|
||||
+ .fd_read = mux_chr_read,
|
||||
+ .fd_event = mux_chr_event,
|
||||
+};
|
||||
+
|
||||
static void mux_chr_update_read_handler(CharDriverState *chr)
|
||||
{
|
||||
MuxDriver *d = chr->opaque;
|
||||
@@ -451,8 +464,7 @@ static void mux_chr_update_read_handler(CharDriverState *chr)
|
||||
d->chr_event[d->mux_cnt] = chr->chr_event;
|
||||
/* Fix up the real driver with mux routines */
|
||||
if (d->mux_cnt == 0) {
|
||||
- qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read,
|
||||
- mux_chr_event, chr);
|
||||
+ qemu_chr_add_handlers(d->drv, &mux_chr_handlers, chr);
|
||||
}
|
||||
if (d->focus != -1) {
|
||||
mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT);
|
||||
diff --git a/qemu-char.h b/qemu-char.h
|
||||
index 56d9954..7a1924c 100644
|
||||
--- a/qemu-char.h
|
||||
+++ b/qemu-char.h
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef QEMU_CHAR_H
|
||||
#define QEMU_CHAR_H
|
||||
|
||||
+#include <stdbool.h>
|
||||
#include "qemu-common.h"
|
||||
#include "qemu-queue.h"
|
||||
#include "qemu-option.h"
|
||||
@@ -73,6 +74,13 @@ struct CharDriverState {
|
||||
QTAILQ_ENTRY(CharDriverState) next;
|
||||
};
|
||||
|
||||
+typedef struct QemuChrHandlers {
|
||||
+ IOCanReadHandler *fd_can_read;
|
||||
+ IOReadHandler *fd_read;
|
||||
+ IOHandler *fd_write_unblocked;
|
||||
+ IOEventHandler *fd_event;
|
||||
+} QemuChrHandlers;
|
||||
+
|
||||
QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
|
||||
CharDriverState *qemu_chr_open_opts(QemuOpts *opts,
|
||||
void (*init)(struct CharDriverState *s));
|
||||
@@ -83,10 +91,7 @@ void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)
|
||||
GCC_FMT_ATTR(2, 3);
|
||||
int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len);
|
||||
void qemu_chr_send_event(CharDriverState *s, int event);
|
||||
-void qemu_chr_add_handlers(CharDriverState *s,
|
||||
- IOCanReadHandler *fd_can_read,
|
||||
- IOReadHandler *fd_read,
|
||||
- IOEventHandler *fd_event,
|
||||
+void qemu_chr_add_handlers(CharDriverState *s, const QemuChrHandlers *handlers,
|
||||
void *opaque);
|
||||
int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg);
|
||||
void qemu_chr_generic_open(CharDriverState *s);
|
||||
--
|
||||
1.7.4.1
|
||||
|
@ -1,76 +0,0 @@
|
||||
>From da7e6cd863ed0cffe885cd2d3639f92c82baf6e2 Mon Sep 17 00:00:00 2001
|
||||
From: Amit Shah <amit.shah@redhat.com>
|
||||
Date: Mon, 21 Mar 2011 20:32:58 +0100
|
||||
Subject: [PATCH 07/17] iohandlers: Add enable/disable_write_fd_handler() functions
|
||||
|
||||
These will be used to provide a cleaner API for the nonblocking case.
|
||||
|
||||
Signed-off-by: Amit Shah <amit.shah@redhat.com>
|
||||
---
|
||||
qemu-char.h | 3 +++
|
||||
vl.c | 35 +++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 38 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/qemu-char.h b/qemu-char.h
|
||||
index 7a1924c..185377c 100644
|
||||
--- a/qemu-char.h
|
||||
+++ b/qemu-char.h
|
||||
@@ -116,6 +116,9 @@ size_t qemu_chr_mem_osize(const CharDriverState *chr);
|
||||
|
||||
/* async I/O support */
|
||||
|
||||
+void enable_write_fd_handler(int fd, IOHandler *fd_write);
|
||||
+void disable_write_fd_handler(int fd);
|
||||
+
|
||||
int qemu_set_fd_handler2(int fd,
|
||||
IOCanReadHandler *fd_read_poll,
|
||||
IOHandler *fd_read,
|
||||
diff --git a/vl.c b/vl.c
|
||||
index 85c36e3..95f51cb 100644
|
||||
--- a/vl.c
|
||||
+++ b/vl.c
|
||||
@@ -1044,6 +1044,41 @@ typedef struct IOHandlerRecord {
|
||||
static QLIST_HEAD(, IOHandlerRecord) io_handlers =
|
||||
QLIST_HEAD_INITIALIZER(io_handlers);
|
||||
|
||||
+static IOHandlerRecord *find_iohandler(int fd)
|
||||
+{
|
||||
+ IOHandlerRecord *ioh;
|
||||
+
|
||||
+ QLIST_FOREACH(ioh, &io_handlers, next) {
|
||||
+ if (ioh->fd == fd) {
|
||||
+ return ioh;
|
||||
+ }
|
||||
+ }
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+void enable_write_fd_handler(int fd, IOHandler *fd_write)
|
||||
+{
|
||||
+ IOHandlerRecord *ioh;
|
||||
+
|
||||
+ ioh = find_iohandler(fd);
|
||||
+ if (!ioh) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ ioh->fd_write = fd_write;
|
||||
+}
|
||||
+
|
||||
+void disable_write_fd_handler(int fd)
|
||||
+{
|
||||
+ IOHandlerRecord *ioh;
|
||||
+
|
||||
+ ioh = find_iohandler(fd);
|
||||
+ if (!ioh) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ ioh->fd_write = NULL;
|
||||
+}
|
||||
|
||||
/* XXX: fd_read_poll should be suppressed, but an API change is
|
||||
necessary in the character devices to suppress fd_can_read(). */
|
||||
--
|
||||
1.7.3.2
|
||||
|
@ -1,62 +0,0 @@
|
||||
>From daf37480ffe37b3e7a781ff010beb4fa89821c29 Mon Sep 17 00:00:00 2001
|
||||
From: Amit Shah <amit.shah@redhat.com>
|
||||
Date: Mon, 21 Mar 2011 21:41:42 +0100
|
||||
Subject: [PATCH 08/17] char: Add framework for a 'write unblocked' callback
|
||||
|
||||
The char layer can let users know that the driver will block on further
|
||||
input. For users interested in not blocking, they can assign a function
|
||||
pointer that will be called back when the driver becomes writable. This
|
||||
patch just adds the function pointers to the CharDriverState structure,
|
||||
future patches will enable the nonblocking and callback functionality.
|
||||
|
||||
Signed-off-by: Amit Shah <amit.shah@redhat.com>
|
||||
---
|
||||
qemu-char.c | 3 +++
|
||||
qemu-char.h | 5 +++++
|
||||
2 files changed, 8 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/qemu-char.c b/qemu-char.c
|
||||
index 3a31d8b..ce76411 100644
|
||||
--- a/qemu-char.c
|
||||
+++ b/qemu-char.c
|
||||
@@ -206,11 +206,14 @@ void qemu_chr_add_handlers(CharDriverState *s,
|
||||
}
|
||||
s->chr_can_read = handlers->fd_can_read;
|
||||
s->chr_read = handlers->fd_read;
|
||||
+ s->chr_write_unblocked = handlers->fd_write_unblocked;
|
||||
s->chr_event = handlers->fd_event;
|
||||
s->handler_opaque = opaque;
|
||||
if (s->chr_update_read_handler)
|
||||
s->chr_update_read_handler(s);
|
||||
|
||||
+ s->write_blocked = false;
|
||||
+
|
||||
/* We're connecting to an already opened device, so let's make sure we
|
||||
also get the open event */
|
||||
if (s->opened) {
|
||||
diff --git a/qemu-char.h b/qemu-char.h
|
||||
index 185377c..bf06da0 100644
|
||||
--- a/qemu-char.h
|
||||
+++ b/qemu-char.h
|
||||
@@ -61,6 +61,9 @@ struct CharDriverState {
|
||||
IOEventHandler *chr_event;
|
||||
IOCanReadHandler *chr_can_read;
|
||||
IOReadHandler *chr_read;
|
||||
+ IOHandler *chr_write_unblocked;
|
||||
+ void (*chr_enable_write_fd_handler)(struct CharDriverState *chr);
|
||||
+ void (*chr_disable_write_fd_handler)(struct CharDriverState *chr);
|
||||
void *handler_opaque;
|
||||
void (*chr_send_event)(struct CharDriverState *chr, int event);
|
||||
void (*chr_close)(struct CharDriverState *chr);
|
||||
@@ -71,6 +74,8 @@ struct CharDriverState {
|
||||
char *label;
|
||||
char *filename;
|
||||
int opened;
|
||||
+ /* Are we in a blocked state? */
|
||||
+ bool write_blocked;
|
||||
QTAILQ_ENTRY(CharDriverState) next;
|
||||
};
|
||||
|
||||
--
|
||||
1.7.3.2
|
||||
|
@ -1,199 +0,0 @@
|
||||
From 8f5b96bd3bdd4fe7aa80f2f27d51bece8f64f20f Mon Sep 17 00:00:00 2001
|
||||
From: Amit Shah <amit.shah@redhat.com>
|
||||
Date: Mon, 21 Mar 2011 22:00:27 +0100
|
||||
Subject: [PATCH 09/30] char: Update send_all() to handle nonblocking chardev
|
||||
write requests
|
||||
|
||||
The send_all function is modified to return to the caller in case the
|
||||
driver cannot handle any more data. It returns -EAGAIN or
|
||||
WSAEWOULDBLOCK on non-Windows and Windows platforms respectively. This
|
||||
is only done when the caller sets a callback function handler indicating
|
||||
it's not interested in blocking till the driver has written out all the
|
||||
data.
|
||||
|
||||
Currently there's no driver or caller that supports this. Future
|
||||
commits will add such capability.
|
||||
|
||||
Signed-off-by: Amit Shah <amit.shah@redhat.com>
|
||||
---
|
||||
net/socket.c | 4 +-
|
||||
qemu-char.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
|
||||
qemu_socket.h | 2 +-
|
||||
3 files changed, 77 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/net/socket.c b/net/socket.c
|
||||
index 3182b37..5dedd78 100644
|
||||
--- a/net/socket.c
|
||||
+++ b/net/socket.c
|
||||
@@ -56,8 +56,8 @@ static ssize_t net_socket_receive(VLANClientState *nc, const uint8_t *buf, size_
|
||||
uint32_t len;
|
||||
len = htonl(size);
|
||||
|
||||
- send_all(s->fd, (const uint8_t *)&len, sizeof(len));
|
||||
- return send_all(s->fd, buf, size);
|
||||
+ send_all(NULL, s->fd, (const uint8_t *)&len, sizeof(len));
|
||||
+ return send_all(NULL, s->fd, buf, size);
|
||||
}
|
||||
|
||||
static ssize_t net_socket_receive_dgram(VLANClientState *nc, const uint8_t *buf, size_t size)
|
||||
diff --git a/qemu-char.c b/qemu-char.c
|
||||
index ce76411..3f665c9 100644
|
||||
--- a/qemu-char.c
|
||||
+++ b/qemu-char.c
|
||||
@@ -500,7 +500,7 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
-int send_all(int fd, const void *buf, int len1)
|
||||
+static int do_send(int fd, const void *buf, int len1, bool nonblock)
|
||||
{
|
||||
int ret, len;
|
||||
|
||||
@@ -508,9 +508,14 @@ int send_all(int fd, const void *buf, int len1)
|
||||
while (len > 0) {
|
||||
ret = send(fd, buf, len, 0);
|
||||
if (ret < 0) {
|
||||
+ if (nonblock && len1 - len) {
|
||||
+ return len1 - len;
|
||||
+ }
|
||||
errno = WSAGetLastError();
|
||||
if (errno != WSAEWOULDBLOCK) {
|
||||
return -1;
|
||||
+ } else if (errno == WSAEWOULDBLOCK && nonblock) {
|
||||
+ return WSAEWOULDBLOCK;
|
||||
}
|
||||
} else if (ret == 0) {
|
||||
break;
|
||||
@@ -524,7 +529,7 @@ int send_all(int fd, const void *buf, int len1)
|
||||
|
||||
#else
|
||||
|
||||
-int send_all(int fd, const void *_buf, int len1)
|
||||
+static int do_send(int fd, const void *_buf, int len1, bool nonblock)
|
||||
{
|
||||
int ret, len;
|
||||
const uint8_t *buf = _buf;
|
||||
@@ -533,8 +538,15 @@ int send_all(int fd, const void *_buf, int len1)
|
||||
while (len > 0) {
|
||||
ret = write(fd, buf, len);
|
||||
if (ret < 0) {
|
||||
- if (errno != EINTR && errno != EAGAIN)
|
||||
+ if (nonblock && len1 - len) {
|
||||
+ return len1 - len;
|
||||
+ }
|
||||
+ if (errno == EAGAIN && nonblock) {
|
||||
+ return -EAGAIN;
|
||||
+ }
|
||||
+ if (errno != EINTR && errno != EAGAIN) {
|
||||
return -1;
|
||||
+ }
|
||||
} else if (ret == 0) {
|
||||
break;
|
||||
} else {
|
||||
@@ -546,6 +558,55 @@ int send_all(int fd, const void *_buf, int len1)
|
||||
}
|
||||
#endif /* !_WIN32 */
|
||||
|
||||
+int send_all(CharDriverState *chr, int fd, const void *_buf, int len1)
|
||||
+{
|
||||
+ int ret, eagain_errno;
|
||||
+ bool nonblock;
|
||||
+
|
||||
+ if (chr && chr->write_blocked) {
|
||||
+ /*
|
||||
+ * We don't handle this situation: the caller should not send
|
||||
+ * us data while we're blocked.
|
||||
+ *
|
||||
+ * We could buffer this data here but that'll only encourage
|
||||
+ * bad behaviour on part of the callers.
|
||||
+ *
|
||||
+ * Also, the data already in fd's buffers isn't easily
|
||||
+ * migratable. If we want full migration support, all the
|
||||
+ * data landing here needs to be buffered and on migration,
|
||||
+ * anything that's unsent needs to be transferred to the
|
||||
+ * dest. machine (which again isn't a very good way of solving
|
||||
+ * the problem, as the src may become writable just during
|
||||
+ * migration and the reader could receive some data twice,
|
||||
+ * essentially corrupting the data).
|
||||
+ */
|
||||
+ abort();
|
||||
+ }
|
||||
+
|
||||
+ nonblock = false;
|
||||
+ /*
|
||||
+ * Ensure the char backend is able to receive and handle the
|
||||
+ * 'write unblocked' event before we turn on nonblock support.
|
||||
+ */
|
||||
+ if (chr && chr->chr_enable_write_fd_handler && chr->chr_write_unblocked) {
|
||||
+ nonblock = true;
|
||||
+ }
|
||||
+ ret = do_send(fd, _buf, len1, nonblock);
|
||||
+
|
||||
+#ifdef _WIN32
|
||||
+ eagain_errno = WSAEWOULDBLOCK;
|
||||
+#else
|
||||
+ eagain_errno = -EAGAIN;
|
||||
+#endif
|
||||
+
|
||||
+ if (nonblock && (ret == eagain_errno || (ret >= 0 && ret < len1))) {
|
||||
+ /* Update fd handler to wake up when chr becomes writable */
|
||||
+ chr->chr_enable_write_fd_handler(chr);
|
||||
+ chr->write_blocked = true;
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
#ifndef _WIN32
|
||||
|
||||
typedef struct {
|
||||
@@ -559,7 +620,7 @@ static int stdio_nb_clients = 0;
|
||||
static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
|
||||
{
|
||||
FDCharDriver *s = chr->opaque;
|
||||
- return send_all(s->fd_out, buf, len);
|
||||
+ return send_all(chr, s->fd_out, buf, len);
|
||||
}
|
||||
|
||||
static int fd_chr_read_poll(void *opaque)
|
||||
@@ -875,7 +936,7 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
|
||||
pty_chr_update_read_handler(chr);
|
||||
return 0;
|
||||
}
|
||||
- return send_all(s->fd, buf, len);
|
||||
+ return send_all(chr, s->fd, buf, len);
|
||||
}
|
||||
|
||||
static int pty_chr_read_poll(void *opaque)
|
||||
@@ -1944,8 +2005,15 @@ static void tcp_closed(void *opaque)
|
||||
static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
|
||||
{
|
||||
TCPCharDriver *s = chr->opaque;
|
||||
+
|
||||
if (s->connected) {
|
||||
- return send_all(s->fd, buf, len);
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = send_all(chr, s->fd, buf, len);
|
||||
+ if (ret == -1 && errno == EPIPE) {
|
||||
+ tcp_closed(chr);
|
||||
+ }
|
||||
+ return ret;
|
||||
} else {
|
||||
/* XXX: indicate an error ? */
|
||||
return len;
|
||||
diff --git a/qemu_socket.h b/qemu_socket.h
|
||||
index 897a8ae..97dd24a 100644
|
||||
--- a/qemu_socket.h
|
||||
+++ b/qemu_socket.h
|
||||
@@ -36,7 +36,7 @@ int inet_aton(const char *cp, struct in_addr *ia);
|
||||
int qemu_socket(int domain, int type, int protocol);
|
||||
int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
|
||||
void socket_set_nonblock(int fd);
|
||||
-int send_all(int fd, const void *buf, int len1);
|
||||
+int send_all(CharDriverState *chr, int fd, const void *buf, int len1);
|
||||
|
||||
/* New, ipv6-ready socket helper functions, see qemu-sockets.c */
|
||||
int inet_listen_opts(QemuOpts *opts, int port_offset);
|
||||
--
|
||||
1.7.5
|
||||
|
@ -1,80 +0,0 @@
|
||||
>From 7d8cbead9454da6dbfdc050c6828faae39621a1b Mon Sep 17 00:00:00 2001
|
||||
From: Amit Shah <amit.shah@redhat.com>
|
||||
Date: Mon, 21 Mar 2011 22:02:47 +0100
|
||||
Subject: [PATCH 10/17] char: Equip the unix/tcp backend to handle nonblocking writes#
|
||||
|
||||
Now that the infrastructure is in place to return -EAGAIN to callers,
|
||||
individual char drivers can set their update_fd_handlers() function to
|
||||
set or remove an fd's write handler. This handler checks if the driver
|
||||
became writable.
|
||||
|
||||
A generic callback routine is used for unblocking writes and letting
|
||||
users of chardevs know that a driver became writable again.
|
||||
|
||||
Signed-off-by: Amit Shah <amit.shah@redhat.com>
|
||||
---
|
||||
qemu-char.c | 34 ++++++++++++++++++++++++++++++++++
|
||||
1 files changed, 34 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/qemu-char.c b/qemu-char.c
|
||||
index eed61d6..7517f64 100644
|
||||
--- a/qemu-char.c
|
||||
+++ b/qemu-char.c
|
||||
@@ -107,6 +107,19 @@
|
||||
static QTAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs =
|
||||
QTAILQ_HEAD_INITIALIZER(chardevs);
|
||||
|
||||
+/*
|
||||
+ * Generic routine that gets called when chardev becomes writable.
|
||||
+ * Lets chardev user know it's OK to send more data.
|
||||
+ */
|
||||
+static void char_write_unblocked(void *opaque)
|
||||
+{
|
||||
+ CharDriverState *chr = opaque;
|
||||
+
|
||||
+ chr->write_blocked = false;
|
||||
+ chr->chr_disable_write_fd_handler(chr);
|
||||
+ chr->chr_write_unblocked(chr->handler_opaque);
|
||||
+}
|
||||
+
|
||||
static void qemu_chr_event(CharDriverState *s, int event)
|
||||
{
|
||||
/* Keep track if the char device is open */
|
||||
@@ -2261,6 +2274,25 @@ static void tcp_chr_close(CharDriverState *chr)
|
||||
qemu_chr_event(chr, CHR_EVENT_CLOSED);
|
||||
}
|
||||
|
||||
+static void tcp_enable_write_fd_handler(CharDriverState *chr)
|
||||
+{
|
||||
+ TCPCharDriver *s = chr->opaque;
|
||||
+
|
||||
+ /*
|
||||
+ * This function is called only after tcp_chr_connect() is called
|
||||
+ * (either in 'server' mode or client mode. So we're sure of
|
||||
+ * s->fd being initialised.
|
||||
+ */
|
||||
+ enable_write_fd_handler(s->fd, char_write_unblocked);
|
||||
+}
|
||||
+
|
||||
+static void tcp_disable_write_fd_handler(CharDriverState *chr)
|
||||
+{
|
||||
+ TCPCharDriver *s = chr->opaque;
|
||||
+
|
||||
+ disable_write_fd_handler(s->fd);
|
||||
+}
|
||||
+
|
||||
static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
|
||||
{
|
||||
CharDriverState *chr = NULL;
|
||||
@@ -2313,6 +2345,8 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
|
||||
chr->chr_write = tcp_chr_write;
|
||||
chr->chr_close = tcp_chr_close;
|
||||
chr->get_msgfd = tcp_get_msgfd;
|
||||
+ chr->chr_enable_write_fd_handler = tcp_enable_write_fd_handler;
|
||||
+ chr->chr_disable_write_fd_handler = tcp_disable_write_fd_handler;
|
||||
|
||||
if (is_listen) {
|
||||
s->listen_fd = fd;
|
||||
--
|
||||
1.7.3.2
|
||||
|
@ -1,56 +0,0 @@
|
||||
From 6a758a4f301d3f8450983d6ef82f3b6dbe0644f4 Mon Sep 17 00:00:00 2001
|
||||
From: Amit Shah <amit.shah@redhat.com>
|
||||
Date: Mon, 21 Mar 2011 22:05:10 +0100
|
||||
Subject: [PATCH 11/30] char: Throttle when host connection is down#
|
||||
|
||||
When the host-side connection goes down, throttle the virtio-serial bus
|
||||
and later unthrottle when a connection gets established. This helps
|
||||
prevent any lost IO (guest->host) while the host connection was down.
|
||||
|
||||
Bugzilla: 621484
|
||||
|
||||
This commit actually helps the bug mentioned above as no writes will now
|
||||
get lost because of the throttling done here. With just the patches
|
||||
sent earlier for that bug, one write will end up getting lost in the
|
||||
worst case (host d/c, guest write, host connect).
|
||||
|
||||
Signed-off-by: Amit Shah <amit.shah@redhat.com>
|
||||
---
|
||||
qemu-char.c | 14 ++++++++++++++
|
||||
1 files changed, 14 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/qemu-char.c b/qemu-char.c
|
||||
index 49e61ba..72c0ce8 100644
|
||||
--- a/qemu-char.c
|
||||
+++ b/qemu-char.c
|
||||
@@ -141,6 +141,9 @@ static void qemu_chr_generic_open_bh(void *opaque)
|
||||
{
|
||||
CharDriverState *s = opaque;
|
||||
qemu_chr_event(s, CHR_EVENT_OPENED);
|
||||
+ if (s->write_blocked) {
|
||||
+ char_write_unblocked(s);
|
||||
+ }
|
||||
qemu_bh_delete(s->bh);
|
||||
s->bh = NULL;
|
||||
}
|
||||
@@ -2025,6 +2028,17 @@ static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
|
||||
ret = send_all(chr, s->fd, buf, len);
|
||||
if (ret == -1 && errno == EPIPE) {
|
||||
tcp_closed(chr);
|
||||
+
|
||||
+ if (chr->chr_enable_write_fd_handler && chr->chr_write_unblocked) {
|
||||
+ /*
|
||||
+ * Since we haven't written out anything, let's say
|
||||
+ * we're throttled. This will prevent any output from
|
||||
+ * the guest getting lost if host-side chardev goes
|
||||
+ * down. Unthrottle when we re-connect.
|
||||
+ */
|
||||
+ chr->write_blocked = true;
|
||||
+ return 0;
|
||||
+ }
|
||||
}
|
||||
return ret;
|
||||
} else {
|
||||
--
|
||||
1.7.5
|
||||
|
@ -1,48 +0,0 @@
|
||||
>From 94e8b44e4fdfbf312e54b78ca7bbb95271cc83ae Mon Sep 17 00:00:00 2001
|
||||
From: Amit Shah <amit.shah@redhat.com>
|
||||
Date: Mon, 21 Mar 2011 22:06:41 +0100
|
||||
Subject: [PATCH 12/17] virtio-console: Enable port throttling when chardev is slow to consume data
|
||||
|
||||
When a chardev indicates it can't accept more data, we tell the
|
||||
virtio-serial code to stop sending us any more data till we tell
|
||||
otherwise. This helps in guests continuing to run normally while the vq
|
||||
keeps getting full and eventually the guest stops queueing more data.
|
||||
As soon as the chardev indicates it can accept more data, start pushing!
|
||||
|
||||
Signed-off-by: Amit Shah <amit.shah@redhat.com>
|
||||
---
|
||||
hw/virtio-console.c | 11 +++++++++++
|
||||
1 files changed, 11 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/hw/virtio-console.c b/hw/virtio-console.c
|
||||
index 22cf28c..eecbdf7 100644
|
||||
--- a/hw/virtio-console.c
|
||||
+++ b/hw/virtio-console.c
|
||||
@@ -18,6 +18,16 @@ typedef struct VirtConsole {
|
||||
CharDriverState *chr;
|
||||
} VirtConsole;
|
||||
|
||||
+/*
|
||||
+ * Callback function that's called from chardevs when backend becomes
|
||||
+ * writable.
|
||||
+ */
|
||||
+static void chr_write_unblocked(void *opaque)
|
||||
+{
|
||||
+ VirtConsole *vcon = opaque;
|
||||
+
|
||||
+ virtio_serial_throttle_port(&vcon->port, false);
|
||||
+}
|
||||
|
||||
/* Callback function that's called when the guest sends us data */
|
||||
static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
|
||||
@@ -61,6 +71,7 @@ static const QemuChrHandlers chr_handlers = {
|
||||
.fd_can_read = chr_can_read,
|
||||
.fd_read = chr_read,
|
||||
.fd_event = chr_event,
|
||||
+ .fd_write_unblocked = chr_write_unblocked,
|
||||
};
|
||||
|
||||
static int generic_port_init(VirtConsole *vcon, VirtIOSerialDevice *dev)
|
||||
--
|
||||
1.7.3.2
|
||||
|
@ -1,133 +0,0 @@
|
||||
>From 06ad256d2939aea4086428dcb5e5e7d5f86eb335 Mon Sep 17 00:00:00 2001
|
||||
From: Alon Levy <alevy@redhat.com>
|
||||
Date: Tue, 22 Mar 2011 12:27:59 +0200
|
||||
Subject: [PATCH 13/17] spice-qemu-char.c: add throttling
|
||||
|
||||
BZ: 672191
|
||||
|
||||
upstream: not submitted (explained below)
|
||||
|
||||
Adds throttling support to spicevmc chardev. Uses a timer to avoid recursing:
|
||||
1. spice-server: reds.c: read_from_vdi_port
|
||||
2. qemu: spice-qemu-char.c: vmc_read
|
||||
3. chr_write_unblocked
|
||||
(calls virtio_serial_throttle_port(port, false))
|
||||
4. qemu: virtio ...
|
||||
5. qemu: spice-qemu-char.c: spice_chr_write
|
||||
6. qemu: spice-qemu-char.c: wakeup (calls into spice-server)
|
||||
7. spice-server: ...
|
||||
8. qemu: spice-qemu-char.c: vmc_read
|
||||
|
||||
Instead, in vmc_read if we were throttled and we are just about to return
|
||||
all the bytes we will set a timer to be triggered immediately to call
|
||||
chr_write_unblocked. Then we return after 2 above, and 3 is called from the
|
||||
timer callback. This also means we can later remove some ugly recursion protection
|
||||
from spice-server.
|
||||
|
||||
The other tricky point in this patch is not returning the leftover chunk twice.
|
||||
When we throttle, by definition we have data that spice server didn't consume.
|
||||
It is being kept by virtio-serial, and by us. The next vmc_read callback needs
|
||||
to not return it, but just do unthrottling. Then virtio will give us the remaining
|
||||
chunk as usual in spice_chr_write, and we will pass it to spice server in the
|
||||
next vmc_read.
|
||||
|
||||
This patch relies on Amit's series to expose throttling to chardev's, which
|
||||
was not accepted upstream, and will not be accepted upstream until the mainloop
|
||||
is reworked to use glib.
|
||||
---
|
||||
spice-qemu-char.c | 39 +++++++++++++++++++++++++++++++++++----
|
||||
1 files changed, 35 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
|
||||
index 517f337..91467d5 100644
|
||||
--- a/spice-qemu-char.c
|
||||
+++ b/spice-qemu-char.c
|
||||
@@ -1,4 +1,6 @@
|
||||
#include "config-host.h"
|
||||
+#include "qemu-common.h"
|
||||
+#include "qemu-timer.h"
|
||||
#include "trace.h"
|
||||
#include "ui/qemu-spice.h"
|
||||
#include <spice.h>
|
||||
@@ -25,6 +27,7 @@ typedef struct SpiceCharDriver {
|
||||
uint8_t *datapos;
|
||||
ssize_t bufsize, datalen;
|
||||
uint32_t debug;
|
||||
+ QEMUTimer *unblock_timer;
|
||||
} SpiceCharDriver;
|
||||
|
||||
static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
|
||||
@@ -51,6 +54,17 @@ static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
|
||||
return out;
|
||||
}
|
||||
|
||||
+static void spice_chr_unblock(void *opaque)
|
||||
+{
|
||||
+ SpiceCharDriver *scd = opaque;
|
||||
+
|
||||
+ if (scd->chr->chr_write_unblocked == NULL) {
|
||||
+ dprintf(scd, 1, "%s: backend doesn't support unthrottling.\n", __func__);
|
||||
+ return;
|
||||
+ }
|
||||
+ scd->chr->chr_write_unblocked(scd->chr->handler_opaque);
|
||||
+}
|
||||
+
|
||||
static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
|
||||
{
|
||||
SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
|
||||
@@ -62,9 +76,16 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
|
||||
scd->datapos += bytes;
|
||||
scd->datalen -= bytes;
|
||||
assert(scd->datalen >= 0);
|
||||
- if (scd->datalen == 0) {
|
||||
- scd->datapos = 0;
|
||||
- }
|
||||
+ }
|
||||
+ if (scd->datalen == 0 && scd->chr->write_blocked) {
|
||||
+ dprintf(scd, 1, "%s: unthrottling (%d)\n", __func__, bytes);
|
||||
+ scd->chr->write_blocked = false;
|
||||
+ /*
|
||||
+ * set a timer instead of calling scd->chr->chr_write_unblocked directly,
|
||||
+ * because that will call back into spice_chr_write (see
|
||||
+ * virtio-console.c:chr_write_unblocked), which is unwanted.
|
||||
+ */
|
||||
+ qemu_mod_timer(scd->unblock_timer, 0);
|
||||
}
|
||||
trace_spice_vmc_read(bytes, len);
|
||||
return bytes;
|
||||
@@ -107,6 +128,7 @@ static void vmc_unregister_interface(SpiceCharDriver *scd)
|
||||
static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
|
||||
{
|
||||
SpiceCharDriver *s = chr->opaque;
|
||||
+ int read_bytes;
|
||||
|
||||
dprintf(s, 2, "%s: %d\n", __func__, len);
|
||||
vmc_register_interface(s);
|
||||
@@ -119,7 +141,15 @@ static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
|
||||
s->datapos = s->buffer;
|
||||
s->datalen = len;
|
||||
spice_server_char_device_wakeup(&s->sin);
|
||||
- return len;
|
||||
+ read_bytes = len - s->datalen;
|
||||
+ if (read_bytes != len) {
|
||||
+ dprintf(s, 1, "%s: throttling: %d < %d (%zd)\n", __func__,
|
||||
+ read_bytes, len, s->bufsize);
|
||||
+ s->chr->write_blocked = true;
|
||||
+ /* We'll get passed in the unconsumed data with the next call */
|
||||
+ s->datalen = 0;
|
||||
+ }
|
||||
+ return read_bytes;
|
||||
}
|
||||
|
||||
static void spice_chr_close(struct CharDriverState *chr)
|
||||
@@ -183,6 +213,7 @@ CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
|
||||
chr->opaque = s;
|
||||
chr->chr_write = spice_chr_write;
|
||||
chr->chr_close = spice_chr_close;
|
||||
+ s->unblock_timer = qemu_new_timer(vm_clock, spice_chr_unblock, s);
|
||||
|
||||
qemu_chr_generic_open(chr);
|
||||
|
||||
--
|
||||
1.7.3.2
|
||||
|
@ -1,71 +0,0 @@
|
||||
>From 6ce8a141a37387a5138d0361cbe92885130010fe Mon Sep 17 00:00:00 2001
|
||||
From: Alon Levy <alevy@redhat.com>
|
||||
Date: Tue, 22 Mar 2011 12:28:00 +0200
|
||||
Subject: [PATCH 14/17] spice-qemu-char.c: remove intermediate buffer
|
||||
|
||||
BZ: 672191
|
||||
upstream: not submitted (explained below)
|
||||
|
||||
virtio-serial's buffer is valid when it calls us, and we don't
|
||||
access it otherwise: vmc_read is only called in response to wakeup,
|
||||
or else we set datalen=0 and throttle. Then vmc_read is called back,
|
||||
we return 0 (not accessing the buffer) and set the timer to unthrottle.
|
||||
|
||||
Also make datalen int and not ssize_t (to fit spice_chr_write signature).
|
||||
|
||||
This relied on the previous patch that introduces throttling, which
|
||||
can't go upstream right now as explained in that patch.
|
||||
---
|
||||
spice-qemu-char.c | 18 ++++++------------
|
||||
1 files changed, 6 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
|
||||
index 91467d5..ed7851e 100644
|
||||
--- a/spice-qemu-char.c
|
||||
+++ b/spice-qemu-char.c
|
||||
@@ -23,9 +23,8 @@ typedef struct SpiceCharDriver {
|
||||
SpiceCharDeviceInstance sin;
|
||||
char *subtype;
|
||||
bool active;
|
||||
- uint8_t *buffer;
|
||||
- uint8_t *datapos;
|
||||
- ssize_t bufsize, datalen;
|
||||
+ const uint8_t *datapos;
|
||||
+ int datalen;
|
||||
uint32_t debug;
|
||||
QEMUTimer *unblock_timer;
|
||||
} SpiceCharDriver;
|
||||
@@ -70,7 +69,7 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
|
||||
SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
|
||||
int bytes = MIN(len, scd->datalen);
|
||||
|
||||
- dprintf(scd, 2, "%s: %p %d/%d/%zd\n", __func__, scd->datapos, len, bytes, scd->datalen);
|
||||
+ dprintf(scd, 2, "%s: %p %d/%d/%d\n", __func__, scd->datapos, len, bytes, scd->datalen);
|
||||
if (bytes > 0) {
|
||||
memcpy(buf, scd->datapos, bytes);
|
||||
scd->datapos += bytes;
|
||||
@@ -133,18 +132,13 @@ static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
|
||||
dprintf(s, 2, "%s: %d\n", __func__, len);
|
||||
vmc_register_interface(s);
|
||||
assert(s->datalen == 0);
|
||||
- if (s->bufsize < len) {
|
||||
- s->bufsize = len;
|
||||
- s->buffer = qemu_realloc(s->buffer, s->bufsize);
|
||||
- }
|
||||
- memcpy(s->buffer, buf, len);
|
||||
- s->datapos = s->buffer;
|
||||
+ s->datapos = buf;
|
||||
s->datalen = len;
|
||||
spice_server_char_device_wakeup(&s->sin);
|
||||
read_bytes = len - s->datalen;
|
||||
if (read_bytes != len) {
|
||||
- dprintf(s, 1, "%s: throttling: %d < %d (%zd)\n", __func__,
|
||||
- read_bytes, len, s->bufsize);
|
||||
+ dprintf(s, 1, "%s: throttling: %d < %d\n", __func__,
|
||||
+ read_bytes, len);
|
||||
s->chr->write_blocked = true;
|
||||
/* We'll get passed in the unconsumed data with the next call */
|
||||
s->datalen = 0;
|
||||
--
|
||||
1.7.3.2
|
||||
|
@ -1,76 +0,0 @@
|
||||
>From c8cb28f0791ab38945c7facb5a63e445b4b6f41f Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Fri, 18 Mar 2011 15:23:21 +0100
|
||||
Subject: [PATCH 15/17] chardev: Allow frontends to notify backends of guest open / close
|
||||
|
||||
Some frontends know when the guest has opened the "channel" and is actively
|
||||
listening to it, for example virtio-serial. This patch adds 2 new qemu-chardev
|
||||
functions which can be used by frontends to signal guest open / close, and
|
||||
allows interested backends to listen to this.
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
---
|
||||
qemu-char.c | 17 +++++++++++++++++
|
||||
qemu-char.h | 4 ++++
|
||||
2 files changed, 21 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/qemu-char.c b/qemu-char.c
|
||||
index 2ef972f..d52eb51 100644
|
||||
--- a/qemu-char.c
|
||||
+++ b/qemu-char.c
|
||||
@@ -507,6 +507,9 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
|
||||
chr->chr_write = mux_chr_write;
|
||||
chr->chr_update_read_handler = mux_chr_update_read_handler;
|
||||
chr->chr_accept_input = mux_chr_accept_input;
|
||||
+ /* Frontend guest-open / -close notification is not support with muxes */
|
||||
+ chr->chr_guest_open = NULL;
|
||||
+ chr->chr_guest_close = NULL;
|
||||
|
||||
/* Muxes are always open on creation */
|
||||
qemu_chr_generic_open(chr);
|
||||
@@ -2712,6 +2715,20 @@ void qemu_chr_set_echo(struct CharDriverState *chr, bool echo)
|
||||
}
|
||||
}
|
||||
|
||||
+void qemu_chr_guest_open(struct CharDriverState *chr)
|
||||
+{
|
||||
+ if (chr->chr_guest_open) {
|
||||
+ chr->chr_guest_open(chr);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void qemu_chr_guest_close(struct CharDriverState *chr)
|
||||
+{
|
||||
+ if (chr->chr_guest_close) {
|
||||
+ chr->chr_guest_close(chr);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void qemu_chr_close(CharDriverState *chr)
|
||||
{
|
||||
QTAILQ_REMOVE(&chardevs, chr, next);
|
||||
diff --git a/qemu-char.h b/qemu-char.h
|
||||
index bf06da0..f3b9bf4 100644
|
||||
--- a/qemu-char.h
|
||||
+++ b/qemu-char.h
|
||||
@@ -69,6 +69,8 @@ struct CharDriverState {
|
||||
void (*chr_close)(struct CharDriverState *chr);
|
||||
void (*chr_accept_input)(struct CharDriverState *chr);
|
||||
void (*chr_set_echo)(struct CharDriverState *chr, bool echo);
|
||||
+ void (*chr_guest_open)(struct CharDriverState *chr);
|
||||
+ void (*chr_guest_close)(struct CharDriverState *chr);
|
||||
void *opaque;
|
||||
QEMUBH *bh;
|
||||
char *label;
|
||||
@@ -91,6 +93,8 @@ CharDriverState *qemu_chr_open_opts(QemuOpts *opts,
|
||||
void (*init)(struct CharDriverState *s));
|
||||
CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s));
|
||||
void qemu_chr_set_echo(struct CharDriverState *chr, bool echo);
|
||||
+void qemu_chr_guest_open(struct CharDriverState *chr);
|
||||
+void qemu_chr_guest_close(struct CharDriverState *chr);
|
||||
void qemu_chr_close(CharDriverState *chr);
|
||||
void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)
|
||||
GCC_FMT_ATTR(2, 3);
|
||||
--
|
||||
1.7.3.2
|
||||
|
@ -1,49 +0,0 @@
|
||||
>From 3baf76e384c04f58f032632c078860d66c8c9db3 Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Fri, 18 Mar 2011 15:30:45 +0100
|
||||
Subject: [PATCH 16/17] virtio-console: notify backend of guest open / close
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
---
|
||||
hw/virtio-console.c | 18 ++++++++++++++++++
|
||||
1 files changed, 18 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/hw/virtio-console.c b/hw/virtio-console.c
|
||||
index eecbdf7..828a1a3 100644
|
||||
--- a/hw/virtio-console.c
|
||||
+++ b/hw/virtio-console.c
|
||||
@@ -37,6 +37,22 @@ static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
|
||||
return qemu_chr_write(vcon->chr, buf, len);
|
||||
}
|
||||
|
||||
+/* Callback function that's called when the guest opens the port */
|
||||
+static void guest_open(VirtIOSerialPort *port)
|
||||
+{
|
||||
+ VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
|
||||
+
|
||||
+ qemu_chr_guest_open(vcon->chr);
|
||||
+}
|
||||
+
|
||||
+/* Callback function that's called when the guest closes the port */
|
||||
+static void guest_close(VirtIOSerialPort *port)
|
||||
+{
|
||||
+ VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
|
||||
+
|
||||
+ qemu_chr_guest_close(vcon->chr);
|
||||
+}
|
||||
+
|
||||
/* Readiness of the guest to accept data on a port */
|
||||
static int chr_can_read(void *opaque)
|
||||
{
|
||||
@@ -81,6 +97,8 @@ static int generic_port_init(VirtConsole *vcon, VirtIOSerialDevice *dev)
|
||||
if (vcon->chr) {
|
||||
qemu_chr_add_handlers(vcon->chr, &chr_handlers, vcon);
|
||||
vcon->port.info->have_data = flush_buf;
|
||||
+ vcon->port.info->guest_open = guest_open;
|
||||
+ vcon->port.info->guest_close = guest_close;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
--
|
||||
1.7.3.2
|
||||
|
@ -1,49 +0,0 @@
|
||||
>From c169795bed5374f0071af201da2dd32b3c5a2417 Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Fri, 18 Mar 2011 15:35:27 +0100
|
||||
Subject: [PATCH 17/17] spice-chardev: listen to frontend guest open / close
|
||||
|
||||
Note the vmc_register_interface() in spice_chr_write is left in place
|
||||
in case someone uses spice-chardev with a frontend which does not have
|
||||
guest open / close notification.
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
---
|
||||
spice-qemu-char.c | 14 ++++++++++++++
|
||||
1 files changed, 14 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
|
||||
index ed7851e..343146c 100644
|
||||
--- a/spice-qemu-char.c
|
||||
+++ b/spice-qemu-char.c
|
||||
@@ -155,6 +155,18 @@ static void spice_chr_close(struct CharDriverState *chr)
|
||||
qemu_free(s);
|
||||
}
|
||||
|
||||
+static void spice_chr_guest_open(struct CharDriverState *chr)
|
||||
+{
|
||||
+ SpiceCharDriver *s = chr->opaque;
|
||||
+ vmc_register_interface(s);
|
||||
+}
|
||||
+
|
||||
+static void spice_chr_guest_close(struct CharDriverState *chr)
|
||||
+{
|
||||
+ SpiceCharDriver *s = chr->opaque;
|
||||
+ vmc_unregister_interface(s);
|
||||
+}
|
||||
+
|
||||
static void print_allowed_subtypes(void)
|
||||
{
|
||||
const char** psubtype;
|
||||
@@ -207,6 +219,8 @@ CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
|
||||
chr->opaque = s;
|
||||
chr->chr_write = spice_chr_write;
|
||||
chr->chr_close = spice_chr_close;
|
||||
+ chr->chr_guest_open = spice_chr_guest_open;
|
||||
+ chr->chr_guest_close = spice_chr_guest_close;
|
||||
s->unblock_timer = qemu_new_timer(vm_clock, spice_chr_unblock, s);
|
||||
|
||||
qemu_chr_generic_open(chr);
|
||||
--
|
||||
1.7.3.2
|
||||
|
@ -1,56 +0,0 @@
|
||||
>From 7a9e7aaa30abf42879d3f13b41679513045c31ec Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Tue, 22 Mar 2011 16:28:41 +0100
|
||||
Subject: [PATCH 18/18] spice-qemu-char: Fix flow control in client -> guest direction
|
||||
|
||||
In the old spice-vmc device we used to have:
|
||||
last_out = virtio_serial_write(&svc->port, p, MIN(len, VMC_MAX_HOST_WRITE));
|
||||
if (last_out > 0)
|
||||
...
|
||||
|
||||
Now in the chardev backend we have:
|
||||
last_out = MIN(len, VMC_MAX_HOST_WRITE);
|
||||
qemu_chr_read(scd->chr, p, last_out);
|
||||
if (last_out > 0) {
|
||||
...
|
||||
|
||||
Which causes us to no longer detect if the virtio port is not ready
|
||||
to receive data from us. chardev actually has a mechanism to detect this,
|
||||
but it requires a separate call to qemu_chr_can_read, before calling
|
||||
qemu_chr_read (which return void).
|
||||
|
||||
This patch uses qemu_chr_can_read to fix the flow control from client to
|
||||
guest.
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
---
|
||||
spice-qemu-char.c | 11 +++++------
|
||||
1 files changed, 5 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
|
||||
index 343146c..def713a 100644
|
||||
--- a/spice-qemu-char.c
|
||||
+++ b/spice-qemu-char.c
|
||||
@@ -38,14 +38,13 @@ static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
|
||||
|
||||
while (len > 0) {
|
||||
last_out = MIN(len, VMC_MAX_HOST_WRITE);
|
||||
- qemu_chr_read(scd->chr, p, last_out);
|
||||
- if (last_out > 0) {
|
||||
- out += last_out;
|
||||
- len -= last_out;
|
||||
- p += last_out;
|
||||
- } else {
|
||||
+ if (qemu_chr_can_read(scd->chr) < last_out) {
|
||||
break;
|
||||
}
|
||||
+ qemu_chr_read(scd->chr, p, last_out);
|
||||
+ out += last_out;
|
||||
+ len -= last_out;
|
||||
+ p += last_out;
|
||||
}
|
||||
|
||||
dprintf(scd, 3, "%s: %lu/%zd\n", __func__, out, len + out);
|
||||
--
|
||||
1.7.3.2
|
||||
|
@ -1,37 +0,0 @@
|
||||
From: Justin M. Forbes <jforbes@redhat.com>
|
||||
Date: Thu, Aug 19 09:13:45 2010 -0500
|
||||
Subject: pc: Add a Fedora-13 machine type for backwards compatibility.
|
||||
|
||||
In Fedora 13 a fedora-13 machine type was added as default to allow
|
||||
interaction with upstream stable qemu which did not support the same
|
||||
feature set. As a result we need to support this machine type through
|
||||
the Fedora 15 release.
|
||||
|
||||
|
||||
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
|
||||
index 9e4bac8..eb1ed05 100644
|
||||
--- a/hw/pc_piix.c
|
||||
+++ b/hw/pc_piix.c
|
||||
@@ -266,6 +266,14 @@ static QEMUMachine pc_machine_v0_13 = {
|
||||
},
|
||||
};
|
||||
|
||||
+static QEMUMachine pc_machine_f13 = {
|
||||
+ .name = "fedora-13",
|
||||
+ .desc = "Standard PC",
|
||||
+ .init = pc_init_pci,
|
||||
+ .max_cpus = 255,
|
||||
+ .is_default = 0,
|
||||
+};
|
||||
+
|
||||
static QEMUMachine pc_machine_v0_12 = {
|
||||
.name = "pc-0.12",
|
||||
.desc = "Standard PC",
|
||||
@@ -397,6 +405,7 @@ static QEMUMachine isapc_machine = {
|
||||
static void pc_machine_init(void)
|
||||
{
|
||||
qemu_register_machine(&pc_machine);
|
||||
+ qemu_register_machine(&pc_machine_f13);
|
||||
qemu_register_machine(&pc_machine_v0_13);
|
||||
qemu_register_machine(&pc_machine_v0_12);
|
||||
qemu_register_machine(&pc_machine_v0_11);
|
87
qemu.spec
87
qemu.spec
@ -1,7 +1,9 @@
|
||||
%define githead 525e3df
|
||||
|
||||
Summary: QEMU is a FAST! processor emulator
|
||||
Name: qemu
|
||||
Version: 0.14.0
|
||||
Release: 9%{?dist}
|
||||
Version: 0.15.0
|
||||
Release: 0.1.20110718%githead%{?dist}
|
||||
# Epoch because we pushed a qemu-1.0 package
|
||||
Epoch: 2
|
||||
License: GPLv2+ and LGPLv2+ and BSD
|
||||
@ -17,7 +19,12 @@ URL: http://www.qemu.org/
|
||||
%define _smp_mflags %{nil}
|
||||
%endif
|
||||
|
||||
Source0: http://downloads.sourceforge.net/sourceforge/kvm/qemu-kvm-%{version}.tar.gz
|
||||
# Source0: http://downloads.sourceforge.net/sourceforge/kvm/qemu-kvm-%{version}.tar.gz
|
||||
# The source for this package was pulled from upstream's git. Use the
|
||||
# following commands to generate the tarball:
|
||||
# git archive --format=tar --prefix=qemu-kvm-0.15/ 525e3df | gzip > qemu-kvm-0.15.0-525e3df.tar.gz
|
||||
Source0: qemu-kvm-%{version}-%{githead}.tar.gz
|
||||
|
||||
Source1: qemu.init
|
||||
|
||||
# Loads kvm kernel modules at boot
|
||||
@ -33,35 +40,6 @@ Source6: ksmtuned.init
|
||||
Source7: ksmtuned
|
||||
Source8: ksmtuned.conf
|
||||
|
||||
# This patch must be carried through F-15 to support guests created
|
||||
# with F-13/
|
||||
Patch00: pc-add-a-Fedora-13-machine-type-for-backward-compat.patch
|
||||
|
||||
# Patches from upstream:
|
||||
Patch01: qemu-fix-non-PCI-target-build.patch
|
||||
Patch02: qemu-vhost-fix-dirty-page-handling.patch
|
||||
|
||||
# Spice fixes
|
||||
Patch20: 0001-qxl-spice-display-move-pipe-to-ssd.patch
|
||||
Patch21: 0002-qxl-implement-get_command-in-vga-mode-without-locks.patch
|
||||
Patch22: 0003-qxl-spice-remove-qemu_mutex_-un-lock_iothread-around.patch
|
||||
Patch23: 0004-hw-qxl-render-drop-cursor-locks-replace-with-pipe.patch
|
||||
Patch24: 0005-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch
|
||||
Patch25: 0006-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch
|
||||
Patch26: 0007-iohandlers-Add-enable-disable_write_fd_handler-funct.patch
|
||||
Patch27: 0008-char-Add-framework-for-a-write-unblocked-callback.patch
|
||||
Patch28: 0009-char-Update-send_all-to-handle-nonblocking-chardev-w.patch
|
||||
Patch29: 0010-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch
|
||||
Patch30: 0011-char-Throttle-when-host-connection-is-down.patch
|
||||
Patch31: 0012-virtio-console-Enable-port-throttling-when-chardev-i.patch
|
||||
Patch32: 0013-spice-qemu-char.c-add-throttling.patch
|
||||
Patch33: 0014-spice-qemu-char.c-remove-intermediate-buffer.patch
|
||||
Patch34: 0015-chardev-Allow-frontends-to-notify-backends-of-guest-.patch
|
||||
Patch35: 0016-virtio-console-notify-backend-of-guest-open-close.patch
|
||||
Patch36: 0017-spice-chardev-listen-to-frontend-guest-open-close.patch
|
||||
Patch37: 0018-spice-qemu-char-Fix-flow-control-in-client-guest-dir.patch
|
||||
|
||||
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
BuildRequires: SDL-devel zlib-devel which texi2html gnutls-devel cyrus-sasl-devel
|
||||
BuildRequires: libaio-devel
|
||||
@ -235,29 +213,6 @@ such as kvm_stat.
|
||||
%prep
|
||||
%setup -q -n qemu-kvm-%{version}
|
||||
|
||||
%patch00 -p1
|
||||
%patch01 -p1
|
||||
%patch02 -p1
|
||||
|
||||
%patch20 -p1
|
||||
%patch21 -p1
|
||||
%patch22 -p1
|
||||
%patch23 -p1
|
||||
%patch24 -p1
|
||||
%patch25 -p1
|
||||
%patch26 -p1
|
||||
%patch27 -p1
|
||||
%patch28 -p1
|
||||
%patch29 -p1
|
||||
%patch30 -p1
|
||||
%patch31 -p1
|
||||
%patch32 -p1
|
||||
%patch33 -p1
|
||||
%patch34 -p1
|
||||
%patch35 -p1
|
||||
%patch36 -p1
|
||||
%patch37 -p1
|
||||
|
||||
%build
|
||||
# By default we build everything, but allow x86 to build a minimal version
|
||||
# with only similar arch target support
|
||||
@ -297,6 +252,7 @@ sed -i.debug 's/"-g $CFLAGS"/"$CFLAGS"/g' configure
|
||||
%ifarch x86_64
|
||||
--enable-spice \
|
||||
%endif
|
||||
--disable-werror \
|
||||
--disable-xen
|
||||
|
||||
echo "config-host.mak contents:"
|
||||
@ -369,22 +325,25 @@ install -D -p -m 0644 -t ${RPM_BUILD_ROOT}%{qemudocdir} Changelog README TODO CO
|
||||
install -D -p -m 0644 qemu.sasl $RPM_BUILD_ROOT%{_sysconfdir}/sasl2/qemu.conf
|
||||
|
||||
rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/pxe*bin
|
||||
rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/pxe*rom
|
||||
rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/gpxe*rom
|
||||
rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/vgabios*bin
|
||||
rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/bios.bin
|
||||
rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/openbios-ppc
|
||||
rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/openbios-sparc32
|
||||
rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/openbios-sparc64
|
||||
rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/petalogix-s3adsp1800.dtb
|
||||
rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/petalogix*.dtb
|
||||
rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/s390-zipl.rom
|
||||
rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/bamboo.dtb
|
||||
rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/slof.bin
|
||||
rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/spapr-rtas.bin
|
||||
rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/ppc_rom.bin
|
||||
|
||||
# the pxe gpxe images will be symlinks to the images on
|
||||
# /usr/share/gpxe, as QEMU doesn't know how to look
|
||||
# for other paths, yet.
|
||||
pxe_link() {
|
||||
ln -s ../gpxe/$2.rom %{buildroot}%{_datadir}/%{name}/pxe-$1.bin
|
||||
ln -s ../gpxe/$2.rom %{buildroot}%{_datadir}/%{name}/pxe-$1.rom
|
||||
}
|
||||
|
||||
pxe_link e1000 8086100e
|
||||
@ -500,17 +459,18 @@ fi
|
||||
%{_datadir}/%{name}/bios.bin
|
||||
%{_datadir}/%{name}/linuxboot.bin
|
||||
%{_datadir}/%{name}/multiboot.bin
|
||||
%{_datadir}/%{name}/mpc8544ds.dtb
|
||||
%{_datadir}/%{name}/vapic.bin
|
||||
%{_datadir}/%{name}/vgabios.bin
|
||||
%{_datadir}/%{name}/vgabios-cirrus.bin
|
||||
%{_datadir}/%{name}/vgabios-qxl.bin
|
||||
%{_datadir}/%{name}/vgabios-stdvga.bin
|
||||
%{_datadir}/%{name}/vgabios-vmware.bin
|
||||
%{_datadir}/%{name}/pxe-e1000.bin
|
||||
%{_datadir}/%{name}/pxe-virtio.bin
|
||||
%{_datadir}/%{name}/pxe-pcnet.bin
|
||||
%{_datadir}/%{name}/pxe-rtl8139.bin
|
||||
%{_datadir}/%{name}/pxe-ne2k_pci.bin
|
||||
%{_datadir}/%{name}/pxe-e1000.rom
|
||||
%{_datadir}/%{name}/pxe-virtio.rom
|
||||
%{_datadir}/%{name}/pxe-pcnet.rom
|
||||
%{_datadir}/%{name}/pxe-rtl8139.rom
|
||||
%{_datadir}/%{name}/pxe-ne2k_pci.rom
|
||||
%config(noreplace) %{_sysconfdir}/qemu/target-x86_64.conf
|
||||
|
||||
%ifarch %{ix86} x86_64
|
||||
@ -561,6 +521,9 @@ fi
|
||||
%{_mandir}/man1/qemu-img.1*
|
||||
|
||||
%changelog
|
||||
* Mon Jul 18 2011 Justin M. Forbes <jforbes@redhat.com> - 2:0.15.0-0.1.20110718525e3df
|
||||
- Update to git snapshot as we prepare for 0.15.0 release
|
||||
|
||||
* Wed Jun 22 2011 Richard W.M. Jones <rjones@redhat.com> - 2:0.14.0-9
|
||||
- Add BR libattr-devel. This caused the -fstype option to be disabled.
|
||||
https://www.redhat.com/archives/libvir-list/2011-June/thread.html#01017
|
||||
|
Loading…
Reference in New Issue
Block a user