On Using Tasklets': An Example of The Linux Kernel's Tasklet' Mechanism For Deferring Some Interrupt-Handling Work

Download as odp, pdf, or txt
Download as odp, pdf, or txt
You are on page 1of 21

On using ‘tasklets’

An example of the Linux kernel’s


‘tasklet’ mechanism for deferring
some interrupt-handling work
Recall purpose of Project #2
• Allow you to gain experience encountering
the kinds of issues that commonly arise in
crafting software to operate real hardware:
– Learning the hardware device’s capabilities
– Deciding which driver-methods to implement
– Accommodating your platform’s interfaces
– Exploiting the OS kernel’s support-functions
– Devising a strategy for testing and debugging
Driver enhancements
• Now that you’ve had an opportunity to get
acquainted with the NS16550 serial UART
(its documented capabilities and its quirks)
we can build upon what you experienced
to contemplate software enhancements
that might not have made much sense if
you lacked any actual confrontation with
‘real-world’ peripheral hardware on PCs
Urgent versus non-urgent
• When some peripheral device issues an
interrupt request, it may need a prompt
response to handle an urgent situation
• After the emergency has been dealt with,
there may also be some further actions
which are necessary, but which can be
safely delayed without jeopardizing the
integrity of proper system functioning
The serial UART
• As an example, when the UART receives
characters via its serial-port, there is only
a limited capability for preserving them in
the device’s on-board ‘receive buffer’
• These received characters need to be
quickly moved out of the UART before
they get overwritten by newer data -- or
before they can cause other incoming
characters to be ‘lost’ for lack of space
The ‘handshake’ lines
• A device-driver for the UART can use the
handshaking signal-lines to regulate the
quantity of data being transmitted to it
• It can de-assert the ‘Clear-To-Send’ signal
being sampled by its equipment partner as
a way to temporarily pause data-transfers
• Once the incoming data-stream is paused,
there is less urgency to move data aside
9-wire null-modem cable
CD CD
RxD RxD
TxD TxD
GND GND
DSR DSR
DTR DTR
RTS RTS
CTS CTS
RI RI
Data Data
Terminal Terminal
Equipment Equipment
the sender the receiver
Modem Control Register

7 6 5 4 3 2 1 0

LOOP
0 0 0 OUT2 OUT1 RTS DTR
BACK

The receiver clears this bit

Legend:
DTR = Data Terminal Ready (1=yes, 0=no)
RTS = Request To Send (1=yes, 0=no)
OUT1 = not used (except in loopback mode)
OUT2 = enables the UART to issue interrupts
LOOPBACK-mode (1=enabled, 0=disabled)
Modem Status Register
The sender checks this bit

7 6 5 4 3 2 1 0

delta delta delta delta


DCD RI DSR CTS
DCD RI DSR CTS

set if the corresponding bit


has changed since the last
time this register was read

Legend: [---- loopback-mode ----]


CTS = Clear To Send (1=yes, 0=no) [bit 0 in Modem Control]
DSR = Data Set Ready (1=yes, 0=no) [bit 1 in Modem Control]
RI = Ring Indicator (1=yes,0=no) [bit 2 in Modem Control]
DCD = Data Carrier Detected (1=yes,0=no) [bit 3 in Modem Control]
The sender’s algorithm

Set RTS=1 in the Modem Control Register

Read the Modem Status Register

CTS==1?
NO
YES

Read the Line Status Register

THRE==1?
NO
YES

Write byte to the Transmit Data Register

DONE
The receiver’s actions
• When the receiver’s storage capacity has
been reached, it takes urgent action to
‘pause’ any further transfers of data (i.e., it
writes ‘0’ to the RTS-bit in its Modem
Control register)
• Then it needs to remove its accumulation
of received data out of its storage medium
• Being less urgent this can be postponed
Interrupt handling
• Often it’s beneficial to separate the actions
a driver performs in responding to a device
interrupt-request into two categories: the
urgent ones are performed immediately,
the less urgent ones temporarily delayed
• Accordingly programmers write separate
functions, known as the “top half” and the
“bottom half” for an interrupt handler
Application to the UART
• Top Half:
– Tell sender to ‘pause’ further data-transfers

• Bottom-Half:
– Move accumulated data out of the device’s
on-board storage-area (e.g., its receive FIFO)
A tasklet for ‘bottom half’ work
• Your device-driver allocates and initializes
a ‘struct tasklet_struct’ object, possessing a
name, a function and a pointer to data
name

function

‘struct tasklet_struct’ object


data-pointer

• Your driver’s ‘top-half’ interrupt-handler will


schedule your tasklet for future execution
Linux syntax
• #include <linux/interrupt.h>

• struct tasklet_struct my_tasklet;


• struct mydata { … } my_tasklet_data;
• void my_function ( unsigned long );

• tasklet_init( &my_tasklet, &my_function,


(unsigned long)&my_tasklet_data );
• tasklet_schedule( &my_tasklet );
• tasklet_kill( &my_tasklet );
Tasklet semantics
• A few technical points to keep in mind if
you decide to make use of ‘tasklets’:
• A ‘tasklet’ runs at ‘interrupt time’ (so it doesn’t own
any user-space context, just kernel-space context)
The kernel-space
kernel context is consistent
space across all tasks

Some interrupted task’s


user context resides here
space (so it can’t be predicted)

‘virtual’ memory
More tasklet semantics…

• A tasklet runs in ‘atomic mode’ (so cannot sleep),


although it can ‘wake up’ a task that is sleeping

• A tasklet executes on the CPU that scheduled it


(and so doesn’t execute concurrently with itself)

• You can schedule your tasklet to run either at


“normal” priority or at “high” priority – the latter
ones all are run before any of the former ones
‘sleep’ versus ‘busy waiting’
• Our ‘tasklet.c’ demo uses the ‘interruptible sleep’
mechanism in its device-driver ‘read()’ method
• Whenever the UART receives new data, it will
interrupt whatever else the CPU is doing
– Quickly our ‘top half’ interrupt-handler pauses any
more data-transfers, schedules our ‘bottom half’ for
future execution, then resumes the interrupted task
– Later our ‘tasklet’ will move accumulated data from
the FIFO to a ringbuffer, then will awaken any task
was sleeping on our ‘read’ function’s wait-queue
The senario overview
READ()
Arrival of new data interrupts the CPU
sleeps until
driver’s ringbuffer
has some data

ISR moves data from


TASKLET
driver’s ringbuffer
stops the sending to user’s buffer
transfers
of additional data received bytes
issues
from UART to
schedules the ‘Clear-To-Send’
to ringbuffer
tasklet if case the
driver’s ringbuffer
wakes up
resumes the has been emptied
sleeping
Interrupted task readers
reports count of
bytes returned
in user’s buffer
‘write()’
• We did not employ efficiency-techniques in
our device-driver’s ‘write()’ function:
– No wait-queues
– No interrupts
– No tasklets

• Thus there is still an opportunity for you to


add improvements to our ‘tasklet.c’ demo!
In-class exercise
• Download our ‘tasklet.c’ module from the
course website, compile it, and install it a
pair of our machines which are connected
to each other via a null-modem cable
• Try testing the ‘robustness’ of our driver:
First launch the ‘cat’ command …
… then redirect lots of screen-output!

$ cat /dev/uart
$ ls -l /usr/bin > /dev/uart

You might also like