From f5e24c5cf77b92ab2737eb230db7ae0b2fb102cc Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <freddy77@gmail.com>
Date: Sat, 17 Sep 2022 09:28:08 +0100
Subject: [PATCH 5/8] 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 6a8b68b..b6a30ad 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)
{
@@ -162,6 +165,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);
@@ -276,6 +280,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)
{
@@ -321,6 +339,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);
@@ -400,13 +419,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:
@@ -427,7 +451,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