From: Jeff Dike <jdike@ka...> - 2001-07-02 07:20:10
> [BTW: what did you mean when you said that there doesn't exist a
> notification when a fd becomes writeable? Isn't that why there are
> syscalls like poll() and select()? Or have I misunderstood something?]
What I meant was that sigio_handler only selects for read. And the irq
mechanism doesn't seem to have a way to say that something is writable
(hardware interrupts are always reads). So, the driver can test for both
reading and writing when it gets called, or we can have separate read and
write irqs for drivers that want them.
Neither sounds very appealing to me offhand.
From: Henrik Nordstrom <hno@ma...> - 2001-07-02 11:28:15
Jeff Dike wrote:
> What I meant was that sigio_handler only selects for read. And the irq
> mechanism doesn't seem to have a way to say that something is writable
> (hardware interrupts are always reads). So, the driver can test for both
> reading and writing when it gets called, or we can have separate read and
> write irqs for drivers that want them.
Serial hardware does interrupts when the write queue has drained below the
low water mark.
Hardware interrupts are just interrupts. What the interrupt signals is up to
the receiving driver by reading it's hardware registers. The shared parts of
the kernel does not care what the interrupt represents.
As UML does not have hardware registers, but uses host resources the
situations is a bit different. Have not studied the UML interrupt
architecture yet, but from my understanding you are using signal driven I/O
combined with select().
The signal indicates some I/O can be performed on the file descriptor.
select() indicates what kind of I/O.
As select() is done in the generic interrupt code and not within each
driver, what you lack is a layer where the drivers can read why the
interrupt has triggered, similar to interrupt status hardware registers of
more traditional hardware interrupt sources.
Notes based on the serial driver:
* terminal and console use is almost completely separated from each other,
mainly to not disturb normal serial operations by console output.
* console writes uses a busy poll method. The kernel may not be allowed to
reschedule within console outputs or wait for interrupts..
* terminal writes uses tty->stopped, tty->hw_stopped, a write queue and
interrupts. Actual writes seem to be done from interrupts only.
* hw_stopped is controlled by the "hardware" driver, set to 1 when waiting
on the hardware
* stopped is controlled by the shared tty_io.c file which implements the
flow control signalling to userspace.
Flow of the serial tty ->write function (rs_write):
copy data to driver transmit buffer
signal the hardware to generate interrupts if not stopped
return amount of data copied to the transmit buffer
Flow of serial interrupt handler: (rs_interrupt)
if receive pending
receive into internal buffer
schedule waiting task
if transmit possible
send from internal queue
if queue is sufficiently drained, schedule waiting task
Flow of serial console ->write function (serial_console_write)
1. Save hardware state
2. Busy-wait for the serial hardware to become available (max 1000000 I/O
polls per character)
3. Output character one at a time
4. loop to 2 if more to send
5. Restore hardware state
The actual userspace flow control seems to be managed by n_tty.c:write_chan,
shared by all tty implementations. Beats me why it is not working. Perhaps
mostly a matter of restrucutring code.
So how should it be done:
a: The hack I made with looping, rescheduling (on the host) and friends
should be done in console_write(), nowhere else.
b: It needs to be figured out why the normal userspace flow controls does
not work. It should work out of the box, but apparently does not (or else
output from userspace applications would not ever be lost).
From: Henrik Nordstrom <hno@ma...> - 2001-07-02 12:27:54
Henrik Nordstrom wrote:
> b: It needs to be figured out why the normal userspace flow controls does
> not work. It should work out of the box, but apparently does not (or else
> output from userspace applications would not ever be lost).
Got it. The fault is in write_room. The generic code assumes that write_room
properly reports the amount of data the driver is ready to accept on small
writes, while the UML stdio_console write_room function always returns 1024.
How to fix:
Do what the other tty drivers does: Use the tty write queue, and a write
interrupt handler to push the data out. Make write_room return the amount of
space available in the write queue.
Things to fix first:
The UML interrupt layer needs to support both read and write interrupts. Exacly
how to signal this down to the interrupt handler needs to be decided upon, but
I guess we could use two fdset_t fields.. (one for read, one for write)
emulating the hardware status bits. Or the interrupt handlers could simply not
care and try to perform both operations to figure out what the interrupt source
There also needs an API whereby the drivers can tell the virtual IRQ source
that they are waiting for a write interrupt on the filedescriptor.
Question: How does the UML IRQ source operate in SMP mode? Is it still only
one, or may there be more than one thread acting as IRQ source?