[Spice-devel] Usb redirection

Hans de Goede hdegoede at redhat.com
Thu Dec 27 02:12:37 PST 2012


Hi,



On 12/27/2012 07:23 AM, Jackson wrote:
> OK! in my situation, my webcam can redirect to VM, then, I open amcap and check
> the code. I find that there are two ways running into the same for loop, and I'm
> not sure it is normal or not?
>
> first route
> the client receive message through usbredir channel, then
> 1. usbredir_handle_msg
> 2. usbredirparser_do_read
> 3. case usb_redir_stop_interrupt_receiving:
>     parser->callb.stop_interrupt_receiving_func(...)
> 4. usbredirhost_stop_interrupt_receiving
> 5. usbredir_write_flush_callback
> 6. usbredirparser_do_write
> 7. in loop, for(;;){}
>
> second route
> another thread run while loop
>     rc = libusb_handle_events(priv->context);
> 1. spice_usb_device_manager_usb_ev_thread
> 2. libusb_handle_events
> 3. libusb_handle_events_timeout_completed
> 4. handle_events
> 5. windows_handle_events
> 6. windows_handle_callback
>     case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
>         windows_transfer_callback(itransfer, io_result, io_size);
> 7. windows_transfer_callback
> 8. usbi_handle_transfer_completion
> 9. usbredirhost_interrupt_packet_complete
> 10. usbredir_write_flush_callback
> 11. usbredirparser_do_write
> 12. in loop, for(;;){}

Yes this is normal, note that both threads can *not* enter the
loop at the same time, as usbredirparser_do_write starts like this:

int usbredirparser_do_write(struct usbredirparser *parser_pub)
{
     struct usbredirparser_priv *parser =
         (struct usbredirparser_priv *)parser_pub;
     struct usbredirparser_buf* wbuf;
     int w, ret = 0;

     LOCK(parser);
     for (;;) {

Notice the LOCK call there, now that may be a nop when the user
of usbredirparser does not use any locks, but spice-gtk
does use the locks, it creates the parser through usbredirhost
with locking functions, from spice-gtk/gtk/gtk/channel-usbredir.c

void spice_usbredir_channel_set_context(SpiceUsbredirChannel *channel,
                                         libusb_context       *context)
{
     SpiceUsbredirChannelPrivate *priv = channel->priv;

     g_return_if_fail(priv->host == NULL);

     priv->context = context;
     priv->host = usbredirhost_open_full(
                                    context, NULL,
                                    usbredir_log,
                                    usbredir_read_callback,
                                    usbredir_write_callback,
                                    usbredir_write_flush_callback,
                                    usbredir_alloc_lock,
                                    usbredir_lock_lock,
                                    usbredir_unlock_lock,
                                    usbredir_free_lock,
                                    channel, PACKAGE_STRING,
                                    spice_util_get_debug() ? usbredirparser_debu
                                    usbredirhost_fl_write_cb_owns_buffer);

Note how it specifies lock alloc, lock, unlock and free functions,
so usbredirhost / usbredirparser will use locking and only one
thread can be running in the for loop at a time (and once the second
thread loop runs it will exit immediately since the flush is already
done).

Regards,

Hans


More information about the Spice-devel mailing list