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; | ... | ... |