any further thoughts on this? On Sun, Dec 12, 2010 at 01:02:41PM +0000, Jacob Meuser wrote: > On Sat, Dec 11, 2010 at 08:56:38PM +0000, Jacob Meuser wrote: > > On Sat, Dec 11, 2010 at 08:35:00PM +0000, Jacob Meuser wrote: > > > On Sat, Dec 11, 2010 at 08:14:24PM +0100, Mark Kettenis wrote: > > > > > Date: Wed, 8 Dec 2010 06:07:30 +0000 > > > > > From: Jacob Meuser <jake...@sdf.lonestar.org> > > > > > > > > > > I recently got a hp officejet 4500. it's a 3-in-1 > > > > > printer/scanner/fax. > > > > > printing works great with the hplip packages. scanning doesn't work > > > > > at > > > > > all. > > > > > > > > > > I tracked the problem to read() failing in usb_bulk_read() in libusb. > > > > > errno was EINTR. so I made this function just continue when read() > > > > > got > > > > > EINTR. I could then scan, but not very reliably. > > > > > > > > > > so I went into the kernel, and tracked it to usbdi_util.c: > > > > > > > > > > @ usbd_bulk_transfer(usbd_xfer_handle xfer, usbd_pipe_ha > > > > > > > > > > error = tsleep((caddr_t)xfer, PZERO | PCATCH, lbl, 0); > > > > > splx(s); > > > > > if (error) { > > > > > DPRINTF(("usbd_bulk_transfer: tsleep=%d\n", error)); > > > > > usbd_abort_pipe(pipe); > > > > > return (USBD_INTERRUPTED); > > > > > } > > > > > > > > > > on a hunch, I changed 'PZERO | PCATCH' to 'PWAIT'. then scanning > > > > > became > > > > > 100% reliable. even full-page 1200dpi (~525MB of data) worked > > > > > perfectly. > > > > > > > > > > great. but, what if we need to interrupt the transfer. we don't want > > > > > to hang here. > > > > > > > > > > well, this function takes a timeout. so, it's possible to make it > > > > > return, even if the transfer stalls. but is this used? I looked > > > > > at the ports that use libusb. setting 0/infinite timeout for bulk > > > > > transfers is extremely rare, only set in code marked experimental > > > > > or problematic. in the kernel, there are however some callers that > > > > > use USBD_NO_TIMEOUT. > > > > > > > > > > so, I offer the following. if there's no timeout, behave like we do > > > > > now and catch signals, and if there's a timeout, ignore signals. > > > > > > > > > > I did the same for interrupt transfers because the situation seems > > > > > to be the same. > > > > > > > > > > thoughts? > > > > > > > > Sorry, but this very much feels like you're hacking around a bug in > > > > the application you're using. If it installs signal handler without > > > > specifying the SA_RESTART flag, it has to deal with read(2) failing > > > > with EINTR. > > > > > > that application would be libusb itself. is a library supposed > > > to be messing with signals? > > > > to be clear, the actual read() is in usb_bulk_read() in libusb. > > so, the application doesn't really know that there's a read(). > > > > I tried making libusb continue, but the problem is that when > > usbd_bulk_transfer catches the signal, it aborts everything in > > the pipe. restarting from there correctly is complicated, > > probably not even possible in a sane way. > > I looked at all users of libusb. none deal with usb_{bulk,interrupt}_read > (the libusb "frontend") quitting with EINTR. none set SA_RESTART. > > usbd_{bulk,intr}_transfer() (in the usb(4) stack) do not obey > SA_RESTART. neither do the ugen(4) ends of those functions. > > usbd_transfer() does not catch signals. in fact. the only other > thing in the usb stack that does catch signals is usbread(), which > is an interface to read messages from the usb event queue. the > event queue is stored in software. it doesn't handle tsleep() > returning ERESTART either, btw. > > figuring out an absolute max timeout seems fairly straight-forward. > timeouts are specified in miliseconds. the usb frame rate is 1000 Hz. > an empty frame signals the end of a transfer. timeout = bytes, > basically. > > now, usbd_intr_transfer() may be a different story. that will block > (if not set or non-blocking io) until there is data to read. most > users of this in libusb do set a timeout though. some also restart > the read if they get ETIMEDOUT. > > I think, catching signals is wrong. at least, it's not expected by > most of it's users and not even handled correctly in the kernel. > > further, by not setting a timeout, it leaves the user to figure out > that something is wrong. > > > > > > > > > > > > > > > > > > Index: usbdi_util.c > > > > > =================================================================== > > > > > RCS file: /cvs/src/sys/dev/usb/usbdi_util.c,v > > > > > retrieving revision 1.25 > > > > > diff -u -p usbdi_util.c > > > > > --- usbdi_util.c 26 Jun 2008 05:42:19 -0000 1.25 > > > > > +++ usbdi_util.c 8 Dec 2010 04:58:49 -0000 > > > > > @@ -426,7 +426,7 @@ usbd_bulk_transfer(usbd_xfer_handle xfer, > > > > > usbd_pipe_ha > > > > > u_int16_t flags, u_int32_t timeout, void *buf, u_int32_t *size, > > > > > char *lbl) > > > > > { > > > > > usbd_status err; > > > > > - int s, error; > > > > > + int s, error, pri; > > > > > > > > > > usbd_setup_xfer(xfer, pipe, 0, buf, *size, flags, timeout, > > > > > usbd_bulk_transfer_cb); > > > > > @@ -437,7 +437,8 @@ usbd_bulk_transfer(usbd_xfer_handle xfer, > > > > > usbd_pipe_ha > > > > > splx(s); > > > > > return (err); > > > > > } > > > > > - error = tsleep((caddr_t)xfer, PZERO | PCATCH, lbl, 0); > > > > > + pri = timeout == USBD_NO_TIMEOUT ? (PZERO | PCATCH) : PWAIT; > > > > > + error = tsleep((caddr_t)xfer, pri, lbl, 0); > > > > > splx(s); > > > > > if (error) { > > > > > DPRINTF(("usbd_bulk_transfer: tsleep=%d\n", error)); > > > > > @@ -467,7 +468,7 @@ usbd_intr_transfer(usbd_xfer_handle xfer, > > > > > usbd_pipe_ha > > > > > u_int16_t flags, u_int32_t timeout, void *buf, u_int32_t *size, > > > > > char *lbl) > > > > > { > > > > > usbd_status err; > > > > > - int s, error; > > > > > + int s, error, pri; > > > > > > > > > > usbd_setup_xfer(xfer, pipe, 0, buf, *size, flags, timeout, > > > > > usbd_intr_transfer_cb); > > > > > @@ -478,7 +479,8 @@ usbd_intr_transfer(usbd_xfer_handle xfer, > > > > > usbd_pipe_ha > > > > > splx(s); > > > > > return (err); > > > > > } > > > > > - error = tsleep(xfer, PZERO | PCATCH, lbl, 0); > > > > > + pri = timeout == USBD_NO_TIMEOUT ? (PZERO | PCATCH) : PWAIT; > > > > > + error = tsleep(xfer, pri, lbl, 0); > > > > > splx(s); > > > > > if (error) { > > > > > DPRINTF(("usbd_intr_transfer: tsleep=%d\n", error)); > > > > > > -- > > > jake...@sdf.lonestar.org > > > SDF Public Access UNIX System - http://sdf.lonestar.org > > > > -- > > jake...@sdf.lonestar.org > > SDF Public Access UNIX System - http://sdf.lonestar.org > > -- > jake...@sdf.lonestar.org > SDF Public Access UNIX System - http://sdf.lonestar.org
-- jake...@sdf.lonestar.org SDF Public Access UNIX System - http://sdf.lonestar.org