Commit 046833eae35d9a8c2ed8e87681a74d6a615a0395
1 parent
5ad265ee
Use a O_NONBLOCK pipe for iso completion signals for thread-safety, by Arnon Gilboa.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3492 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
29 additions
and
22 deletions
usb-linux.c
... | ... | @@ -68,6 +68,7 @@ struct endp_data { |
68 | 68 | typedef struct USBHostDevice { |
69 | 69 | USBDevice dev; |
70 | 70 | int fd; |
71 | + int pipe_fds[2]; | |
71 | 72 | USBPacket *packet; |
72 | 73 | struct endp_data endp_table[MAX_ENDPOINTS]; |
73 | 74 | int configuration; |
... | ... | @@ -78,8 +79,6 @@ typedef struct USBHostDevice { |
78 | 79 | |
79 | 80 | typedef struct PendingURB { |
80 | 81 | struct usbdevfs_urb *urb; |
81 | - USBHostDevice *dev; | |
82 | - QEMUBH *bh; | |
83 | 82 | int status; |
84 | 83 | struct PendingURB *next; |
85 | 84 | } PendingURB; |
... | ... | @@ -91,8 +90,6 @@ static int add_pending_urb(struct usbdevfs_urb *urb) |
91 | 90 | PendingURB *purb = qemu_mallocz(sizeof(PendingURB)); |
92 | 91 | if (purb) { |
93 | 92 | purb->urb = urb; |
94 | - purb->dev = NULL; | |
95 | - purb->bh = NULL; | |
96 | 93 | purb->status = 0; |
97 | 94 | purb->next = pending_urbs; |
98 | 95 | pending_urbs = purb; |
... | ... | @@ -341,16 +338,21 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) |
341 | 338 | } |
342 | 339 | |
343 | 340 | #ifdef USE_ASYNCIO |
344 | -static void usb_linux_bh_cb(void *opaque) | |
341 | +static void urb_completion_pipe_read(void *opaque) | |
345 | 342 | { |
346 | - PendingURB *pending_urb = (PendingURB *)opaque; | |
347 | - USBHostDevice *s = pending_urb->dev; | |
348 | - struct usbdevfs_urb *purb = NULL; | |
343 | + USBHostDevice *s = opaque; | |
349 | 344 | USBPacket *p = s->packet; |
350 | - int ret; | |
345 | + PendingURB *pending_urb = NULL; | |
346 | + struct usbdevfs_urb *purb = NULL; | |
347 | + int len, ret; | |
348 | + | |
349 | + len = read(s->pipe_fds[0], &pending_urb, sizeof(pending_urb)); | |
350 | + if (len != sizeof(pending_urb)) { | |
351 | + printf("urb_completion: error reading pending_urb, len=%d\n", len); | |
352 | + return; | |
353 | + } | |
351 | 354 | |
352 | - /* FIXME: handle purb->status */ | |
353 | - qemu_free(pending_urb->bh); | |
355 | + /* FIXME: handle pending_urb->status */ | |
354 | 356 | del_pending_urb(pending_urb->urb); |
355 | 357 | |
356 | 358 | if (!p) { |
... | ... | @@ -360,14 +362,14 @@ static void usb_linux_bh_cb(void *opaque) |
360 | 362 | |
361 | 363 | ret = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &purb); |
362 | 364 | if (ret < 0) { |
363 | - printf("usb_linux_bh_cb: REAPURBNDELAY ioctl=%d errno=%d\n", | |
365 | + printf("urb_completion: REAPURBNDELAY ioctl=%d errno=%d\n", | |
364 | 366 | ret, errno); |
365 | 367 | return; |
366 | 368 | } |
367 | 369 | |
368 | 370 | #ifdef DEBUG_ISOCH |
369 | 371 | if (purb == pending_urb->urb) { |
370 | - printf("usb_linux_bh_cb: urb mismatch reaped=%p pending=%p\n", | |
372 | + printf("urb_completion: urb mismatch reaped=%p pending=%p\n", | |
371 | 373 | purb, urb); |
372 | 374 | } |
373 | 375 | #endif |
... | ... | @@ -391,12 +393,8 @@ static void isoch_done(int signum, siginfo_t *info, void *context) |
391 | 393 | |
392 | 394 | purb = get_pending_urb(urb); |
393 | 395 | if (purb) { |
394 | - purb->bh = qemu_bh_new(usb_linux_bh_cb, purb); | |
395 | - if (purb->bh) { | |
396 | - purb->dev = s; | |
397 | - purb->status = info->si_errno; | |
398 | - qemu_bh_schedule(purb->bh); | |
399 | - } | |
396 | + purb->status = info->si_errno; | |
397 | + write(s->pipe_fds[1], &purb, sizeof(purb)); | |
400 | 398 | } |
401 | 399 | } |
402 | 400 | #endif |
... | ... | @@ -627,7 +625,7 @@ USBDevice *usb_host_device_open(const char *devname) |
627 | 625 | /* read the device description */ |
628 | 626 | dev->descr_len = read(fd, dev->descr, sizeof(dev->descr)); |
629 | 627 | if (dev->descr_len <= 0) { |
630 | - perror("usb_host_update_interfaces: reading device data failed"); | |
628 | + perror("usb_host_device_open: reading device data failed"); | |
631 | 629 | goto fail; |
632 | 630 | } |
633 | 631 | |
... | ... | @@ -650,7 +648,7 @@ USBDevice *usb_host_device_open(const char *devname) |
650 | 648 | |
651 | 649 | ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci); |
652 | 650 | if (ret < 0) { |
653 | - perror("USBDEVFS_CONNECTINFO"); | |
651 | + perror("usb_host_device_open: USBDEVFS_CONNECTINFO"); | |
654 | 652 | goto fail; |
655 | 653 | } |
656 | 654 | |
... | ... | @@ -688,8 +686,17 @@ USBDevice *usb_host_device_open(const char *devname) |
688 | 686 | sigact.sa_restorer = 0; |
689 | 687 | ret = sigaction(SIG_ISOCOMPLETE, &sigact, NULL); |
690 | 688 | if (ret < 0) { |
691 | - printf("sigaction SIG_ISOCOMPLETE=%d errno=%d\n", ret, errno); | |
689 | + perror("usb_host_device_open: sigaction failed"); | |
690 | + goto fail; | |
691 | + } | |
692 | + | |
693 | + if (pipe(dev->pipe_fds) < 0) { | |
694 | + perror("usb_host_device_open: pipe creation failed"); | |
695 | + goto fail; | |
692 | 696 | } |
697 | + fcntl(dev->pipe_fds[0], F_SETFL, O_NONBLOCK | O_ASYNC); | |
698 | + fcntl(dev->pipe_fds[1], F_SETFL, O_NONBLOCK); | |
699 | + qemu_set_fd_handler(dev->pipe_fds[0], urb_completion_pipe_read, NULL, dev); | |
693 | 700 | #endif |
694 | 701 | dev->urbs_ready = 0; |
695 | 702 | return (USBDevice *)dev; | ... | ... |