[sane-devel] Scanner buttons (kind of RFC)
Matto Marjanovic
maddog at mir.com
Thu Sep 12 20:50:38 BST 2002
>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.
More information about the sane-devel
mailing list