[Spice-devel] [spice-gtk Win32 v4 06/17] Windows mingw: usb: Dynamically install a libusb driver for USB devices

Marc-André Lureau marcandre.lureau at gmail.com
Thu Jul 5 15:28:08 PDT 2012


Hi

some remarks below

On Thu, Jul 5, 2012 at 10:43 PM, Uri Lublin <uril at redhat.com> wrote:
> @@ -635,7 +649,7 @@ static void spice_usb_device_manager_add_dev(SpiceUsbDeviceManager  *self,
>              spice_usb_device_manager_connect_device_async(self,
>                                     device, NULL,
>                                     spice_usb_device_manager_auto_connect_cb,
> -                                   g_object_ref(device));
> +                                   device);

This is a bit worrisome, an async operation should keep a reference on
device, or it must make sure to cancel cleanly when the device is
destroyed.

The spice_usb_device_manager_auto_connect_cb is still doing
spice_usb_device_unref(device), is that normal? see also comment in
03/17

> +    installer = spice_win_usb_driver_new();
> +    cbinfo = g_new0(UsbInstallCbInfo, 1);
> +    cbinfo->manager     = self;
> +    cbinfo->device      = device;
> +    cbinfo->installer   = installer;
> +    cbinfo->cancellable = cancellable;
> +    cbinfo->callback    = callback;
> +    cbinfo->user_data   = user_data;
> +    spice_win_usb_driver_install(installer, device, NULL,
> +                                 spice_usb_device_manager_drv_install_cb,
> +                                 cbinfo);

The same cancellable should be used.


> +static void win_usb_driver_cancelled_cb(GCancellable *cancellable, gpointer user_data)
> +{
> +    SpiceWinUsbDriver *self = SPICE_WIN_USB_DRIVER(user_data);
> +    SpiceWinUsbDriverPrivate *priv = self->priv;
> +
> +    g_message("IN %s result=%p", __FUNCTION__, priv->result);

s/g_message/SPICE_DEBUG

> +    if (priv->result) {
> +        win_usb_driver_async_result_set_cancelled(priv->result);
> +        g_simple_async_result_complete_in_idle(priv->result);
> +    }

I think this isn't really cancelling the operation, it will give the
impression to the caller that it is cancelled, by returning an error.
But there will still be an outstanding/ pending operation that may
cause further errors when calling the clerk etc, the device might be
busy or there might be multiple simulatenous requests etc...

> +    istream = (GInputStream *)gobject;

prefer the safer G_INPUT_STREAM macro over a static cast.

> +
> +    if (bytes != sizeof(priv->reply)) {
> +        g_warning("usbclerk size mismatch: read %d bytes, expected %d (header %d, size in header %d)",
> +                  bytes, sizeof(priv->reply), sizeof(priv->reply.hdr), priv->reply.hdr.size);
> +        /* For now just warn, do not fail */

Although a bit unlikely, this read might be incomplete, so you may
want to re-call read_async with the rest of the buffer in this case
(it seems to happen quite often with the legacy usb)

> +    memset(&req, 0, sizeof(req));

Just a note because it was there a couple of time, a declaration such
as USBClerkDriverOp req = { 0, } is less error-prone and elegant than
calling memset() yourself. No problem!

> +    req.hdr.magic   = USB_CLERK_MAGIC;
> +    req.hdr.version = USB_CLERK_VERSION;
> +    req.hdr.type    = op;
> +    req.hdr.size    = sizeof(req);
> +    req.vid = vid;
> +    req.pid = pid;
> +
> +    ostream = g_win32_output_stream_new(priv->handle, FALSE);
> +
> +    ret = g_output_stream_write_all(ostream, &req, sizeof(req), &bytes, NULL, err);

This is a blocking call, in the main thread, afaict

> +    if (!spice_win_usb_driver_send_request(self, USB_CLERK_DRIVER_INSTALL,
> +                                           vid, pid, &err)) {

So this is blocking op

> +    /* set up for async read */
> +    priv->result = result;

So what happen if there is already an outstanding priv->result?
perhaps it should g_return_if_fail condition at the beginning of this
function?

> +    priv->device = device;

Wouldn't it make sense to ref it since the async operation may
out-live the caller?

> +    if (cancellable) {
> +        priv->cancellable = cancellable;
> +        priv->cancellable_id = g_cancellable_connect(cancellable,
> +                                                     G_CALLBACK(win_usb_driver_cancelled_cb),
> +                                                     self, NULL);
> +    }

This isn't really helping, the signal isn't going to cancel the
operation on a different thread, the cancellable should be passed to
all the async operations.

> +    spice_win_usb_driver_read_reply_async(self);

Here


-- 
Marc-André Lureau


More information about the Spice-devel mailing list