mirror of
https://github.com/torvalds/linux.git
synced 2024-11-13 23:51:39 +00:00
bfb07599da
It's a bit strange to see tty_register_ldisc call in modules' exit functions. Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
199 lines
7.3 KiB
Plaintext
199 lines
7.3 KiB
Plaintext
|
|
The Lockronomicon
|
|
|
|
Your guide to the ancient and twisted locking policies of the tty layer and
|
|
the warped logic behind them. Beware all ye who read on.
|
|
|
|
FIXME: still need to work out the full set of BKL assumptions and document
|
|
them so they can eventually be killed off.
|
|
|
|
|
|
Line Discipline
|
|
---------------
|
|
|
|
Line disciplines are registered with tty_register_ldisc() passing the
|
|
discipline number and the ldisc structure. At the point of registration the
|
|
discipline must be ready to use and it is possible it will get used before
|
|
the call returns success. If the call returns an error then it won't get
|
|
called. Do not re-use ldisc numbers as they are part of the userspace ABI
|
|
and writing over an existing ldisc will cause demons to eat your computer.
|
|
After the return the ldisc data has been copied so you may free your own
|
|
copy of the structure. You must not re-register over the top of the line
|
|
discipline even with the same data or your computer again will be eaten by
|
|
demons.
|
|
|
|
In order to remove a line discipline call tty_unregister_ldisc().
|
|
In ancient times this always worked. In modern times the function will
|
|
return -EBUSY if the ldisc is currently in use. Since the ldisc referencing
|
|
code manages the module counts this should not usually be a concern.
|
|
|
|
Heed this warning: the reference count field of the registered copies of the
|
|
tty_ldisc structure in the ldisc table counts the number of lines using this
|
|
discipline. The reference count of the tty_ldisc structure within a tty
|
|
counts the number of active users of the ldisc at this instant. In effect it
|
|
counts the number of threads of execution within an ldisc method (plus those
|
|
about to enter and exit although this detail matters not).
|
|
|
|
Line Discipline Methods
|
|
-----------------------
|
|
|
|
TTY side interfaces:
|
|
|
|
close() - This is called on a terminal when the line
|
|
discipline is being unplugged. At the point of
|
|
execution no further users will enter the
|
|
ldisc code for this tty. Can sleep.
|
|
|
|
open() - Called when the line discipline is attached to
|
|
the terminal. No other call into the line
|
|
discipline for this tty will occur until it
|
|
completes successfully. Can sleep.
|
|
|
|
write() - A process is writing data through the line
|
|
discipline. Multiple write calls are serialized
|
|
by the tty layer for the ldisc. May sleep.
|
|
|
|
flush_buffer() - May be called at any point between open and close.
|
|
|
|
chars_in_buffer() - Report the number of bytes in the buffer.
|
|
|
|
set_termios() - Called on termios structure changes. The caller
|
|
passes the old termios data and the current data
|
|
is in the tty. Called under the termios semaphore so
|
|
allowed to sleep. Serialized against itself only.
|
|
|
|
read() - Move data from the line discipline to the user.
|
|
Multiple read calls may occur in parallel and the
|
|
ldisc must deal with serialization issues. May
|
|
sleep.
|
|
|
|
poll() - Check the status for the poll/select calls. Multiple
|
|
poll calls may occur in parallel. May sleep.
|
|
|
|
ioctl() - Called when an ioctl is handed to the tty layer
|
|
that might be for the ldisc. Multiple ioctl calls
|
|
may occur in parallel. May sleep.
|
|
|
|
Driver Side Interfaces:
|
|
|
|
receive_buf() - Hand buffers of bytes from the driver to the ldisc
|
|
for processing. Semantics currently rather
|
|
mysterious 8(
|
|
|
|
receive_room() - Can be called by the driver layer at any time when
|
|
the ldisc is opened. The ldisc must be able to
|
|
handle the reported amount of data at that instant.
|
|
Synchronization between active receive_buf and
|
|
receive_room calls is down to the driver not the
|
|
ldisc. Must not sleep.
|
|
|
|
write_wakeup() - May be called at any point between open and close.
|
|
The TTY_DO_WRITE_WAKEUP flag indicates if a call
|
|
is needed but always races versus calls. Thus the
|
|
ldisc must be careful about setting order and to
|
|
handle unexpected calls. Must not sleep.
|
|
|
|
The driver is forbidden from calling this directly
|
|
from the ->write call from the ldisc as the ldisc
|
|
is permitted to call the driver write method from
|
|
this function. In such a situation defer it.
|
|
|
|
|
|
Locking
|
|
|
|
Callers to the line discipline functions from the tty layer are required to
|
|
take line discipline locks. The same is true of calls from the driver side
|
|
but not yet enforced.
|
|
|
|
Three calls are now provided
|
|
|
|
ldisc = tty_ldisc_ref(tty);
|
|
|
|
takes a handle to the line discipline in the tty and returns it. If no ldisc
|
|
is currently attached or the ldisc is being closed and re-opened at this
|
|
point then NULL is returned. While this handle is held the ldisc will not
|
|
change or go away.
|
|
|
|
tty_ldisc_deref(ldisc)
|
|
|
|
Returns the ldisc reference and allows the ldisc to be closed. Returning the
|
|
reference takes away your right to call the ldisc functions until you take
|
|
a new reference.
|
|
|
|
ldisc = tty_ldisc_ref_wait(tty);
|
|
|
|
Performs the same function as tty_ldisc_ref except that it will wait for an
|
|
ldisc change to complete and then return a reference to the new ldisc.
|
|
|
|
While these functions are slightly slower than the old code they should have
|
|
minimal impact as most receive logic uses the flip buffers and they only
|
|
need to take a reference when they push bits up through the driver.
|
|
|
|
A caution: The ldisc->open(), ldisc->close() and driver->set_ldisc
|
|
functions are called with the ldisc unavailable. Thus tty_ldisc_ref will
|
|
fail in this situation if used within these functions. Ldisc and driver
|
|
code calling its own functions must be careful in this case.
|
|
|
|
|
|
Driver Interface
|
|
----------------
|
|
|
|
open() - Called when a device is opened. May sleep
|
|
|
|
close() - Called when a device is closed. At the point of
|
|
return from this call the driver must make no
|
|
further ldisc calls of any kind. May sleep
|
|
|
|
write() - Called to write bytes to the device. May not
|
|
sleep. May occur in parallel in special cases.
|
|
Because this includes panic paths drivers generally
|
|
shouldn't try and do clever locking here.
|
|
|
|
put_char() - Stuff a single character onto the queue. The
|
|
driver is guaranteed following up calls to
|
|
flush_chars.
|
|
|
|
flush_chars() - Ask the kernel to write put_char queue
|
|
|
|
write_room() - Return the number of characters tht can be stuffed
|
|
into the port buffers without overflow (or less).
|
|
The ldisc is responsible for being intelligent
|
|
about multi-threading of write_room/write calls
|
|
|
|
ioctl() - Called when an ioctl may be for the driver
|
|
|
|
set_termios() - Called on termios change, serialized against
|
|
itself by a semaphore. May sleep.
|
|
|
|
set_ldisc() - Notifier for discipline change. At the point this
|
|
is done the discipline is not yet usable. Can now
|
|
sleep (I think)
|
|
|
|
throttle() - Called by the ldisc to ask the driver to do flow
|
|
control. Serialization including with unthrottle
|
|
is the job of the ldisc layer.
|
|
|
|
unthrottle() - Called by the ldisc to ask the driver to stop flow
|
|
control.
|
|
|
|
stop() - Ldisc notifier to the driver to stop output. As with
|
|
throttle the serializations with start() are down
|
|
to the ldisc layer.
|
|
|
|
start() - Ldisc notifier to the driver to start output.
|
|
|
|
hangup() - Ask the tty driver to cause a hangup initiated
|
|
from the host side. [Can sleep ??]
|
|
|
|
break_ctl() - Send RS232 break. Can sleep. Can get called in
|
|
parallel, driver must serialize (for now), and
|
|
with write calls.
|
|
|
|
wait_until_sent() - Wait for characters to exit the hardware queue
|
|
of the driver. Can sleep
|
|
|
|
send_xchar() - Send XON/XOFF and if possible jump the queue with
|
|
it in order to get fast flow control responses.
|
|
Cannot sleep ??
|
|
|