<div dir="ltr"><div dir="ltr"><div>Hi,</div><div>As an aside, some discussion around this was had before. There is an issue in the SANE standard repo where we might decide on something:</div><div><br></div><div><a href="https://gitlab.com/sane-project/standard/-/issues/7">https://gitlab.com/sane-project/standard/-/issues/7</a></div><div><br></div><div>Cheers,</div><div>Ralph<br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Dec 8, 2021 at 10:23 AM Paul Wolneykien <<a href="mailto:manowar@altlinux.org">manowar@altlinux.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">3 декабря 2021 г. 19:00:25 GMT+03:00, Paul Wolneykien<br>
<<a href="mailto:manowar@altlinux.org" target="_blank">manowar@altlinux.org</a>> пишет:<br>
>В Fri, 03 Dec 2021 10:34:05 -0500<br>
><a href="mailto:ryniker@ryniker.org" target="_blank">ryniker@ryniker.org</a> пишет:<br>
>> A callback mechanism provides a framework that can naturally avoid<br>
>> missed button events, and can support variations such as capture of<br>
>> "button down" and "button release" events without a requirement for<br>
>> the program with physical access to the hardware to maintain state<br>
>> information until a suitable poll operation is received.<br>
>> <br>
>> A callback design is better able to support multiple<br>
>> buttons. Applications have less need for complex polling operations<br>
>> (three buttons... which was pressed first?) <br>
><br>
>  Then, I'll try to experiment this way with my scanner.<br>
<br>
  I think we have a problem with concurrent SANE access.<br>
<br>
  First of all, the USB abstraction in SANE seems to be thread unsafe:<br>
at least the USB read timeout is set separately from read with<br>
sanei_usb_set_timeout() while the actual reading is done with<br>
sanei_usb_read_*(). With libusb_timeout being a global variable in<br>
sanei_usb.c I don't understand is it possible to work even with two<br>
different devices (scanners) from the same app in parallel?<br>
<br>
  And what about concurrent calls to sane_control_option(),<br>
sane_start() related to the same device from the same app?<br>
It might be possible to synchronize (enqueue) these calls with<br>
saned daemon, but in the simplest local-running case they seem to be<br>
unsynchronized... Is that true?<br>
<br>
  Secondly. With the notification callback scheme we've discussed<br>
earlier (above), it's important not to make the notification calls come<br>
from "nowhere" (a separate thread spawned in the backend). That was<br>
really wrong. The scanning application should explicitly maintain all<br>
the threads that can call its own functions. And there is a known<br>
solution to this problem in libusb: the libusb_handle_events*() set of<br>
functions. However, this approach is really a lighter version of<br>
polling: a polling of the internal state without sending any packets<br>
over USB. We can call this a "software polling" meaning no regular<br>
signals are sent over the wire.<br>
<br>
  So, if we would even try to add a sane_handle_events() in SANE it<br>
would still be a polling solution, a solution requiring polling<br>
procedure in a single-threaded frontend as we can't safely access two<br>
USB endpoints in parallel with SANE.<br>
<br>
  Then, a question arise: can we get a software polling with the<br>
present SANE API? And again I think we can.<br>
<br>
  With adding the new option capability<br>
<br>
+ #define SANE_CAP_EVENT<br>
<br>
  we can mark options which state is safe to be asked as frequently as<br>
you want. Technically this can be achieved by using<br>
sanei_usb_read_int() on scanners with interrupt endpoint for buttons:<br>
that function doesn't sent anything to the device but just checks the<br>
state of the internal queue for the presence of any already received<br>
data (that is pushed by the scanner to the PC).<br>
<br>
  Moreover, reading a SANE_CAP_EVENT option shouldn't just return a<br>
"now" value --- it should return the next available value from the<br>
event queue, as a number of events could have been received by the<br>
time of the read. It should not be "the button is down (up) now at<br>
the moment you ask" as it is now with button options.<br>
<br>
  Having an event queue is the useful approach to work with events,<br>
but only if you have a way to reset the queue and start over: i. e. if<br>
you can throw away meaningless events from the past. And that's also<br>
can be naturally done with the present API: invocation of<br>
SANE_ACTION_SET_VALUE against the event option should do the trick.<br>
<br>
  What about the network (remote scanner) case? I think, that in that<br>
case, a regular polling of SANE_CAP_EVENT options can be done by saned<br>
daemon itself, with some reasonable (and configured) period. In order<br>
to keep it single-threaded the daemon should stop this polling on<br>
reception of a command from the remote frontend (and then, to start it<br>
over being idle again). Then, in the case of an event being read the<br>
daemon should immediately pass it further to the frontend's network<br>
client part, where it should be appended to the internal queue. The<br>
frontend polling procedure would work with that queue under the hood<br>
and wouldn't pollute the network with "read-read-read" commands.<br>
<br>
  Actually, the network pollution is still possible with that scheme<br>
but only with the packets coming from (!) the remote scanner to PC ---<br>
from some mad scanner that is trying to DDoS us! :-)<br>
<br>
  Any comments about this update?<br>
<br>
</blockquote></div></div>