[sane-devel] Device locking, batch scan

Oliver Rauch oliver.rauch@rauch-domain.de
Thu, 12 Sep 2002 23:00:11 +0200

I think the problem is not so hard.
We need a separate way to allow blocking.

I am just adding a batch scan mode to xsane. For this
the frontend needs a possinilty to tell the backend that
we are doing a batch scan.

something like:

option batch-scan-start => first scan
option batch-scan-loop => we are doing several batch scans
option batch-scan-end => this is the last scan

an additional option can helo to speed up things:
option batch-next-tl_y # => tell the scanner where the next scan begins
so the scanhead can be moved to this position between the two scans
(some professional umax scanners do this in the firmware).

the backend has to lock the device when a scan is done
with batch-scan-start active and has to unlock the device when
a scan is done with batch-scan-end.

In all other cases the backend should only lock between sane_start
and sane_cancel.

This is not complete but I think it is a good approach to handle
batch scans and locking.


Matto Marjanovic schrieb:
>  >You ask the wrong question. The people do not close their frontend and this
>  >would make it impossible for the others to scan when the device is locked.
> Man, Oliver, you must have a lot of very cranky and forgetful people where
>  you work; this seems to be a serious problem for you!
> It seems to me that there are two separate issues here:
>   a) Multiple users may need to be able to share one device.
>   b) A backend may need to be able to keep track of the device state
>       over multiple scans.
> With regards to (a):
>  Your solution doesn't really fix the problem.  The problem is that you
>   don't want one user of the device to be able to inadvertently lock out
>   other users.  However, as long as the backend is allowed to have exclusive
>   use of the physical device for longer than the scope of a single sane_*()
>   function call, then this is a possibility.
>  Why?  Because it then depends on the behavior of the frontend.  Here is a
>   simple scenario:  User A starts a long scan, saving to an NFS mounted disk.
>   User A gets bored, leaves for lunch.  A few minutes later, NFS server fails
>   silently somehow, and the frontend is stuck waiting to write disk, between
>   sane_read() calls.  User B decides to scan something, discovers the scanner
>   locked and User A gone, and then he comes screaming into your office.
>  Ok, it's not a very probable scenario, but the whole point is that, given
>   any device locking at all, the responsibility for ensuring cooperative
>   behavior lies in the frontend --- or rather, lies outside the backend.
>   Because nothing you can do in the backend will prevent someone from writing
>   a frontend which hogs the device.
>  So, yes, it is *convenient* for a backend to release the device between
>   most API calls, but that just allows us to ignore the problem, not fix it.
>   A true fix would involve some layer that arbitrates between different
>   clients, and that could aptly go into a network daemon.  (See far below
>   for additional commentary on this.)
> Now, with regards to (b):
>  If a backend needs to keep track of device state over multiple scans,
>   then it needs to be able to guarantee that it has exclusive access to
>   the device for the entire session during which it is controlling the
>   device.  This is not inherently an unreasonable request.  The backend
>   is a device driver after all, albeit operating in user-space.
>  Now the question is how you define a session, and how the API's abstraction
>   of a "device" coincides with the requirements of the actual devices.
>  There are two models on the table:
>    1) The session lasts from sane_open() until sane_close().
>    2) The session lasts from sane_start() until sane_cancel(), except for
>        certain cases (e.g. autofeeder source) in which is lasts over a
>        multiple number of sane_start()/sane_cancel() cycles.
>  How do these translate into the API specification?  Here are some options:
>    Model 1, version A:  The backend is *required* to lock the device
>                         between sane_open() and sane_close().
>    Model 1, version B:  The backend is *allowed* to lock the device
>                         between sane_open() and sane_close().
>    Model 2, version A:  The backend is *allowed* to lock the device
>                         between sane_start() and sane_cancel(), possibly
>                         with nested sane_start() and sane_cancel() calls
>                         if the source is an autofeeder.
>                         (But, this time should be made as short as possible.)
>    Model 2, version B:  The backend is *allowed* to lock the device
>                         as long as it needs to maintain consistent state.
>                         (But, this time should be made as short as possible.)
>   (1B) is the simplest:  it doesn't really say anything.  It makes no
>   guarantees to the caller/frontend, but does indicate that the device
>   may be locked at some point.  Almost equivalent to what the spec already
>   says about this, which is nothing.
>   (1A) is also simple, and it also guarantees that the caller/frontend has
>   complete control of the underlying device for as long as the caller keeps
>   the backend open.  Such a guarantee is useful for implementing access
>   control layers on top of the backend (or multi-user arbitration, etc),
>   but is just as well established by making the device available to only a
>   single system-daemon which does the extra control.  (I can also see the
>   possibility of some oddball backend for an oddball device where it is
>   not actually possible to open the device exclusively, in which case the
>   backend could not make this guarantee by itself anyway.)
>   (2A) is, in terms of requirements and guarantees, equivalent to (1B).
>   The frontend doesn't really know when the device is locked.  Also, there
>   may be devices with a need to maintain state longer than one scan cycle
>   for reasons other than an autofeeder.  For such devices, the natural
>   definition of a "session" conflicts with this model.
>   (2B) is, in terms of requirements and guarantees, equivalent to (1B).
>   The frontend doesn't really know when the device is locked, and the backend
>   can lock the device whenever it wants/needs to.
> Hmmm.
> After all this thinking and writing, I actually come to think that:
>  o The spec is just fine as it is --- perhaps with a (1B) statement
>     added to clarify that a client cannot rely on the backend to keep the
>     device either locked OR free.
>  o Any system that needs to ensure some combination of mutual
>     exclusion or mutual cooperation should make the device accessible
>     only to an intermediary daemon which takes care of such functions.
> -matt m.
> PS:  responses to other points, for those of you still awake:  :)
>  >>         By skipping calibration later, the backend saves time; but if the
>  >>         scanner has become calibrated for the wrong mode, it locks up.  The
>  >>         backend thus has to maintain control of the entire session, since
>  >>         it can't read this state from the scanner.
>  >
>  >Also no problem.  When you start a new session (the device is not
>  >locked when sane_start is called) then you have to do a new
>  >calibration. In general it is senseless to skip calibration for
>  >longer than e.g. half an hour because the light of the lamp does
>  >change in this time so it is necessary to do a new claibration.
> Suppose, as it happens for my Microtek scanner, that the calibration takes
>  5 seconds.  And suppose I want to do fifty small scans, that each take
>  about 15 seconds.
> If the calibration is done before every scan, this job will take me 1000
>  seconds = ~17 minutes.
> If I can have the scanner do the calibration just once, this job will take
>  755 seconds = ~13 minutes.  That saves me 4 minutes (25%).  And it is a
>  lot quieter, too!
>  >> An idea, perhaps for SANE2:  a fancy saned could actually maintain a queue
>  >>  of clients waiting to use the scanner.  This would be great in a large
>  >>  multi-user facility.  If multiple users try to claim the same scanner,
>  >>  the requests line up (with a "pending/waiting/in-use-by-X" message given),
>  >>  and when the scanner is released by the last person, it becomes locked by
>  >>  the next person in line.
>  >
>  >This also does not solve the problem:
>  >When the first one who locked the device does close the frontend then the
>  >next one gets access but he may be at lunch when he gets access. This
>  >does not solve anything.
> That same fancy saned could include a time-out:  if no commands are received
>  for 5 minutes, the user is booted off the scanner, and the next user gets
>  her turn.  Heck, there could be a "maximum turn time" parameter so that
>  no one gets to hog a machine for more than, say, 20 minutes anyway.
>  >I know a lot of people who open several instances of xsane on the same
>  >machine to use different settings.
> In that case, you should make it easier to save/load sets of device settings
>  in xsane, so people don't have to keep 8 separate xsane windows open all
>  day long.

Homepage:	http://www.rauch-domain.de
sane-umax:	http://www.rauch-domain.de/sane-umax
xsane:		http://www.xsane.org
E-Mail:		mailto:Oliver.Rauch@rauch-domain.de