You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
107 lines
3.3 KiB
107 lines
3.3 KiB
2 years ago
|
From 3fcbd4a2569f227ae6fad6a37c8864d33271e5f4 Mon Sep 17 00:00:00 2001
|
||
|
From: Frediano Ziglio <freddy77@gmail.com>
|
||
|
Date: Sat, 17 Sep 2022 09:28:08 +0100
|
||
|
Subject: [PATCH 4/4] Recreate watch if needed
|
||
|
|
||
|
Do not always watch for output buffer.
|
||
|
Watching for output buffer if we don't have nothing to write
|
||
|
(which is the usual case) is consuming a lot of CPU.
|
||
|
|
||
|
This fixes https://gitlab.freedesktop.org/spice/usbredir/-/issues/24.
|
||
|
|
||
|
Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
|
||
|
---
|
||
|
tools/usbredirect.c | 28 ++++++++++++++++++++++++++--
|
||
|
1 file changed, 26 insertions(+), 2 deletions(-)
|
||
|
|
||
|
diff --git a/tools/usbredirect.c b/tools/usbredirect.c
|
||
|
index afe9dee..59452aa 100644
|
||
|
--- a/tools/usbredirect.c
|
||
|
+++ b/tools/usbredirect.c
|
||
|
@@ -29,6 +29,7 @@ typedef struct redirect {
|
||
|
} device;
|
||
|
bool is_client;
|
||
|
bool keepalive;
|
||
|
+ bool watch_inout;
|
||
|
char *addr;
|
||
|
int port;
|
||
|
int verbosity;
|
||
|
@@ -42,6 +43,8 @@ typedef struct redirect {
|
||
|
GMainLoop *main_loop;
|
||
|
} redirect;
|
||
|
|
||
|
+static void create_watch(redirect *self);
|
||
|
+
|
||
|
static bool
|
||
|
parse_opt_device(const char *device, int *vendor, int *product)
|
||
|
{
|
||
|
@@ -163,6 +166,7 @@ parse_opts(int *argc, char ***argv)
|
||
|
}
|
||
|
|
||
|
self = g_new0(redirect, 1);
|
||
|
+ self->watch_inout = true;
|
||
|
if (!parse_opt_device(device, &self->device.vendor, &self->device.product)) {
|
||
|
g_printerr("Failed to parse device: '%s' - expected: vendor:product or busnum-devnum\n", device);
|
||
|
g_clear_pointer(&self, g_free);
|
||
|
@@ -277,6 +281,20 @@ usbredir_log_cb(void *priv, int level, const char *msg)
|
||
|
g_log_structured(G_LOG_DOMAIN, glog_level, "MESSAGE", msg);
|
||
|
}
|
||
|
|
||
|
+static void
|
||
|
+update_watch(redirect *self)
|
||
|
+{
|
||
|
+ const bool watch_inout = usbredirhost_has_data_to_write(self->usbredirhost) != 0;
|
||
|
+ if (watch_inout == self->watch_inout) {
|
||
|
+ return;
|
||
|
+ }
|
||
|
+ g_source_remove(self->watch_server_id);
|
||
|
+ self->watch_server_id = 0;
|
||
|
+ self->watch_inout = watch_inout;
|
||
|
+
|
||
|
+ create_watch(self);
|
||
|
+}
|
||
|
+
|
||
|
static int
|
||
|
usbredir_read_cb(void *priv, uint8_t *data, int count)
|
||
|
{
|
||
|
@@ -322,6 +340,7 @@ usbredir_write_cb(void *priv, uint8_t *data, int count)
|
||
|
if (g_error_matches(err, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
|
||
|
/* Try again later */
|
||
|
nbytes = 0;
|
||
|
+ update_watch(self);
|
||
|
} else {
|
||
|
if (err != NULL) {
|
||
|
g_warning("Failure at %s: %s", __func__, err->message);
|
||
|
@@ -401,13 +420,18 @@ connection_handle_io_cb(GIOChannel *source, GIOCondition condition, gpointer use
|
||
|
goto end;
|
||
|
}
|
||
|
}
|
||
|
- if (condition & G_IO_OUT) {
|
||
|
+ // try to write data in any case, to avoid having another iteration and
|
||
|
+ // creation of another watch if there is space in output buffer
|
||
|
+ if (usbredirhost_has_data_to_write(self->usbredirhost) != 0) {
|
||
|
int ret = usbredirhost_write_guest_data(self->usbredirhost);
|
||
|
if (ret < 0) {
|
||
|
g_critical("%s: Failed to write to guest", __func__);
|
||
|
goto end;
|
||
|
}
|
||
|
}
|
||
|
+
|
||
|
+ // update the watch if needed
|
||
|
+ update_watch(self);
|
||
|
return G_SOURCE_CONTINUE;
|
||
|
|
||
|
end:
|
||
|
@@ -428,7 +452,7 @@ create_watch(redirect *self)
|
||
|
#endif
|
||
|
|
||
|
self->watch_server_id = g_io_add_watch(io_channel,
|
||
|
- G_IO_IN | G_IO_OUT | G_IO_HUP | G_IO_ERR,
|
||
|
+ G_IO_IN | G_IO_HUP | G_IO_ERR | (self->watch_inout ? G_IO_OUT : 0),
|
||
|
connection_handle_io_cb,
|
||
|
self);
|
||
|
}
|
||
|
--
|
||
|
2.39.0
|
||
|
|