[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