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,6 +68,7 @@ struct endp_data { | ||
68 | typedef struct USBHostDevice { | 68 | typedef struct USBHostDevice { |
69 | USBDevice dev; | 69 | USBDevice dev; |
70 | int fd; | 70 | int fd; |
71 | + int pipe_fds[2]; | ||
71 | USBPacket *packet; | 72 | USBPacket *packet; |
72 | struct endp_data endp_table[MAX_ENDPOINTS]; | 73 | struct endp_data endp_table[MAX_ENDPOINTS]; |
73 | int configuration; | 74 | int configuration; |
@@ -78,8 +79,6 @@ typedef struct USBHostDevice { | @@ -78,8 +79,6 @@ typedef struct USBHostDevice { | ||
78 | 79 | ||
79 | typedef struct PendingURB { | 80 | typedef struct PendingURB { |
80 | struct usbdevfs_urb *urb; | 81 | struct usbdevfs_urb *urb; |
81 | - USBHostDevice *dev; | ||
82 | - QEMUBH *bh; | ||
83 | int status; | 82 | int status; |
84 | struct PendingURB *next; | 83 | struct PendingURB *next; |
85 | } PendingURB; | 84 | } PendingURB; |
@@ -91,8 +90,6 @@ static int add_pending_urb(struct usbdevfs_urb *urb) | @@ -91,8 +90,6 @@ static int add_pending_urb(struct usbdevfs_urb *urb) | ||
91 | PendingURB *purb = qemu_mallocz(sizeof(PendingURB)); | 90 | PendingURB *purb = qemu_mallocz(sizeof(PendingURB)); |
92 | if (purb) { | 91 | if (purb) { |
93 | purb->urb = urb; | 92 | purb->urb = urb; |
94 | - purb->dev = NULL; | ||
95 | - purb->bh = NULL; | ||
96 | purb->status = 0; | 93 | purb->status = 0; |
97 | purb->next = pending_urbs; | 94 | purb->next = pending_urbs; |
98 | pending_urbs = purb; | 95 | pending_urbs = purb; |
@@ -341,16 +338,21 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) | @@ -341,16 +338,21 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) | ||
341 | } | 338 | } |
342 | 339 | ||
343 | #ifdef USE_ASYNCIO | 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 | USBPacket *p = s->packet; | 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 | del_pending_urb(pending_urb->urb); | 356 | del_pending_urb(pending_urb->urb); |
355 | 357 | ||
356 | if (!p) { | 358 | if (!p) { |
@@ -360,14 +362,14 @@ static void usb_linux_bh_cb(void *opaque) | @@ -360,14 +362,14 @@ static void usb_linux_bh_cb(void *opaque) | ||
360 | 362 | ||
361 | ret = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &purb); | 363 | ret = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &purb); |
362 | if (ret < 0) { | 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 | ret, errno); | 366 | ret, errno); |
365 | return; | 367 | return; |
366 | } | 368 | } |
367 | 369 | ||
368 | #ifdef DEBUG_ISOCH | 370 | #ifdef DEBUG_ISOCH |
369 | if (purb == pending_urb->urb) { | 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 | purb, urb); | 373 | purb, urb); |
372 | } | 374 | } |
373 | #endif | 375 | #endif |
@@ -391,12 +393,8 @@ static void isoch_done(int signum, siginfo_t *info, void *context) | @@ -391,12 +393,8 @@ static void isoch_done(int signum, siginfo_t *info, void *context) | ||
391 | 393 | ||
392 | purb = get_pending_urb(urb); | 394 | purb = get_pending_urb(urb); |
393 | if (purb) { | 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 | #endif | 400 | #endif |
@@ -627,7 +625,7 @@ USBDevice *usb_host_device_open(const char *devname) | @@ -627,7 +625,7 @@ USBDevice *usb_host_device_open(const char *devname) | ||
627 | /* read the device description */ | 625 | /* read the device description */ |
628 | dev->descr_len = read(fd, dev->descr, sizeof(dev->descr)); | 626 | dev->descr_len = read(fd, dev->descr, sizeof(dev->descr)); |
629 | if (dev->descr_len <= 0) { | 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 | goto fail; | 629 | goto fail; |
632 | } | 630 | } |
633 | 631 | ||
@@ -650,7 +648,7 @@ USBDevice *usb_host_device_open(const char *devname) | @@ -650,7 +648,7 @@ USBDevice *usb_host_device_open(const char *devname) | ||
650 | 648 | ||
651 | ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci); | 649 | ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci); |
652 | if (ret < 0) { | 650 | if (ret < 0) { |
653 | - perror("USBDEVFS_CONNECTINFO"); | 651 | + perror("usb_host_device_open: USBDEVFS_CONNECTINFO"); |
654 | goto fail; | 652 | goto fail; |
655 | } | 653 | } |
656 | 654 | ||
@@ -688,8 +686,17 @@ USBDevice *usb_host_device_open(const char *devname) | @@ -688,8 +686,17 @@ USBDevice *usb_host_device_open(const char *devname) | ||
688 | sigact.sa_restorer = 0; | 686 | sigact.sa_restorer = 0; |
689 | ret = sigaction(SIG_ISOCOMPLETE, &sigact, NULL); | 687 | ret = sigaction(SIG_ISOCOMPLETE, &sigact, NULL); |
690 | if (ret < 0) { | 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 | #endif | 700 | #endif |
694 | dev->urbs_ready = 0; | 701 | dev->urbs_ready = 0; |
695 | return (USBDevice *)dev; | 702 | return (USBDevice *)dev; |