<html><head><meta http-equiv="Content-Type" content="text/html charset=us-ascii"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On 1 Mar 2016, at 24:06 AM, Jonathon Jongsma <<a href="mailto:jjongsma@redhat.com" class="">jjongsma@redhat.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">On Sun, 2016-02-28 at 11:54 +0200, Dmitry Fleytman wrote:</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">This patch fixes device list change notification handing<br class="">logic for cases when more than one device being plugged<br class="">or unplugged simultaneously.<br class=""><br class="">The simplest way to reproduce the problematic scenario<br class="">is (un)plugging of a usb HUB with a few devices inserted.<br class=""><br class="">Signed-off-by: Dmitry Fleytman <<a href="mailto:dmitry@daynix.com" class="">dmitry@daynix.com</a>><br class="">---<br class="">src/win-usb-dev.c | 82 +++++++++++++++++++-----------------------------------<br class="">-<br class="">1 file changed, 28 insertions(+), 54 deletions(-)<br class=""><br class="">diff --git a/src/win-usb-dev.c b/src/win-usb-dev.c<br class="">index 1e4b2d6..1b4d353 100644<br class="">--- a/src/win-usb-dev.c<br class="">+++ b/src/win-usb-dev.c<br class="">@@ -34,7 +34,6 @@<br class=""><br class="">struct _GUdevClientPrivate {<br class="">    libusb_context *ctx;<br class="">-    gssize udev_list_size;<br class="">    GList *udev_list;<br class="">    HWND hwnd;<br class="">};<br class="">@@ -196,9 +195,7 @@ g_udev_client_initable_init(GInitable *initable,<br class="">GCancellable *cancellable,<br class="">    }<br class=""><br class="">    /* get initial device list */<br class="">-    priv->udev_list_size = g_udev_client_list_devices(self, &priv->udev_list,<br class="">-                                                      err, __FUNCTION__);<br class="">-    if (priv->udev_list_size < 0) {<br class="">+    if (g_udev_client_list_devices(self, &priv->udev_list, err, __FUNCTION__)<br class="">< 0) {<br class="">        goto g_udev_client_init_failed;<br class="">    }<br class=""><br class="">@@ -339,74 +336,51 @@ static gboolean gudev_devices_are_equal(GUdevDevice *a,<br class="">GUdevDevice *b)<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Immediately above this line is the following comment:</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">/* Assumes each event stands for a single device change (at most) */</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Since you're changing the function to handle multiple insertions or removals at</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">once, we should probably remove this comment.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""></div></blockquote><div><br class=""></div><div>Right, I forgot to drop it. Removed.</div><br class=""><blockquote type="cite" class=""><div class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">static void handle_dev_change(GUdevClient *self)<br class="">{<br class="">    GUdevClientPrivate *priv = self->priv;<br class="">-    GUdevDevice *changed_dev = NULL;<br class="">-    ssize_t dev_count;<br class="">-    int is_dev_change;<br class="">    GError *err = NULL;<br class="">    GList *now_devs = NULL;<br class="">-    GList *llist, *slist; /* long-list and short-list*/<br class="">-    GList *lit, *sit; /* iterators for long-list and short-list */<br class="">-    GUdevDevice *ldev, *sdev; /* devices on long-list and short-list */<br class="">+    GList *prev, *curr; /* iterators for previous and current device lists */<br class=""><br class="">-    dev_count = g_udev_client_list_devices(self, &now_devs, &err,<br class="">-                                           __FUNCTION__);<br class="">-    g_return_if_fail(dev_count >= 0);<br class="">-<br class="">-    SPICE_DEBUG("number of current devices %"G_GSSIZE_FORMAT<br class="">-                ", I know about %"G_GSSIZE_FORMAT" devices",<br class="">-                dev_count, priv->udev_list_size);<br class="">-<br class="">-    is_dev_change = dev_count - priv->udev_list_size;<br class="">-    if (is_dev_change == 0) {<br class="">-        g_udev_client_free_device_list(&now_devs);<br class="">+    if(g_udev_client_list_devices(self, &now_devs, &err, __FUNCTION__) < 0) {<br class="">+        g_warning("could not retrieve device list");<br class="">        return;<br class="">    }<br class=""><br class="">-    if (is_dev_change > 0) {<br class="">-        llist  = now_devs;<br class="">-        slist = priv->udev_list;<br class="">-    } else {<br class="">-        llist = priv->udev_list;<br class="">-        slist  = now_devs;<br class="">-    }<br class="">-<br class="">-    g_udev_device_print_list(llist, "handle_dev_change: long list:");<br class="">-    g_udev_device_print_list(slist, "handle_dev_change: short list:");<br class="">+    g_udev_device_print_list(now_devs, "handle_dev_change: current list:");<br class="">+    g_udev_device_print_list(priv->udev_list, "handle_dev_change: previous<br class="">list:");<br class=""><br class="">-    /* Go over the longer list */<br class="">-    for (lit = g_list_first(llist); lit != NULL; lit=g_list_next(lit)) {<br class="">-        ldev = lit->data;<br class="">-        /* Look for dev in the shorther list */<br class="">-        for (sit = g_list_first(slist); sit != NULL; sit=g_list_next(sit)) {<br class="">-            sdev = sit->data;<br class="">-            if (gudev_devices_are_equal(ldev, sdev))<br class="">+    /* Unregister devices that are not present anymore */<br class="">+    for (prev = g_list_first(priv->udev_list); prev != NULL; prev =<br class="">g_list_next(prev)) {<br class="">+        /* Look for dev in the current list */<br class="">+        for (curr = g_list_first(now_devs); curr != NULL; curr =<span class="Apple-converted-space"> </span><br class="">g_list_next(curr)) {<br class="">+            if (gudev_devices_are_equal(prev->data, curr->data))<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">g_list_find_custom() is a possibility here</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""></div></blockquote><div><br class=""></div><div><br class=""></div><div>Ok.</div><br class=""><blockquote type="cite" class=""><div class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">                break;<br class="">        }<br class="">-        if (sit == NULL) {<br class="">-            /* Found a device which appears only in the longer list */<br class="">-            changed_dev = ldev;<br class="">-            break;<br class="">+<br class="">+        if (curr == NULL) {<br class="">+            /* Found a device that was removed */<br class="">+            g_udev_device_print(prev->data, "<<< USB device removed");<br class="">+            g_signal_emit(self, signals[UEVENT_SIGNAL], 0, "remove", prev<br class="">->data);<br class="">        }<br class="">    }<br class=""><br class="">-    if (!changed_dev) {<br class="">-        g_warning("couldn't find any device change");<br class="">-        goto leave;<br class="">-    }<br class="">+    /* Register newly inserted devices */<br class="">+    for (curr = g_list_first(now_devs); curr != NULL; curr =<br class="">g_list_next(curr)) {<br class="">+        /* Look for dev in the previous list */<br class="">+        for (prev = g_list_first(priv->udev_list); prev != NULL; prev =<br class="">g_list_next(prev)) {<br class="">+            if (gudev_devices_are_equal(prev->data, curr->data))<br class="">+                break;<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">and here</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""></div></blockquote><div><br class=""></div><div>Actually these nested loops are similar in both cases so in the next version I moved those to a separate function and used g_list_find_custom() as you suggested.</div><br class=""><blockquote type="cite" class=""><div class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">+        }<br class=""><br class="">-    if (is_dev_change > 0) {<br class="">-        g_udev_device_print(changed_dev, ">>> USB device inserted");<br class="">-        g_signal_emit(self, signals[UEVENT_SIGNAL], 0, "add", changed_dev);<br class="">-    } else {<br class="">-        g_udev_device_print(changed_dev, "<<< USB device removed");<br class="">-        g_signal_emit(self, signals[UEVENT_SIGNAL], 0, "remove",<br class="">changed_dev);<br class="">+        if (prev == NULL) {<br class="">+            /* Found a device that was inserted */<br class="">+            g_udev_device_print(curr->data, ">>> USB device inserted");<br class="">+            g_signal_emit(self, signals[UEVENT_SIGNAL], 0, "add", curr<br class="">->data);<br class="">+        }<br class="">    }<br class=""><br class="">-leave:<br class="">    /* keep most recent info: free previous list, and keep current list */<br class="">    g_udev_client_free_device_list(&priv->udev_list);<br class="">    priv->udev_list = now_devs;<br class="">-    priv->udev_list_size = dev_count;<br class="">}<br class=""><br class="">static LRESULT CALLBACK wnd_proc(HWND hwnd, UINT message, WPARAM wparam,<br class="">LPARAM lparam)<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Acked-by: Jonathon Jongsma <</span><a href="mailto:jjongsma@redhat.com" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">jjongsma@redhat.com</a><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">></span></div></blockquote></div><br class=""></body></html>