A ringbuffer application - PowerPoint PPT Presentation

About This Presentation
Title:

A ringbuffer application

Description:

Introduction to process blocking' and the Linux kernel's support for sleeping' and waking' ... kernel puts a task to sleep by simply modifying the value of ... – PowerPoint PPT presentation

Number of Views:89
Avg rating:3.0/5.0
Slides: 27
Provided by: CRU7
Learn more at: https://www.cs.usfca.edu
Category:

less

Transcript and Presenter's Notes

Title: A ringbuffer application


1
A ringbuffer application
  • Introduction to process blocking and the Linux
    kernels support for sleeping and waking

2
Devices might be idle
  • With our previous device-driver examples (i.e.,
    dram, cmosram), the data to be read was already
    there, just waiting to be input
  • But with certain other character devices, such as
    a keyboard, a program may want to input its data
    before any new data has actually been entered by
    a user
  • In such cases we prefer to wait until data
    arrives rather than to abandon reading

3
Devices might be busy
  • Sometimes an application wants to write some
    data to a character device, such as a printer,
    but the device temporarily is not able to accept
    more data, being still busy with processing
    previously written data
  • Again, in such situations we prefer to just wait
    until the device becomes ready for us to send it
    more data rather than to give up

4
We could do busy waiting
  • It is possible for a device-driver to poll a
    status-bit continuously until data is ready, (or
    until a device is no longer too busy)
  • Such a technique is called busy waiting
  • But it could waste a lot of valuable CPU time
    before any benefit was realized!

do status inb( 0x64 ) while ( (
status READY ) 0 )
5
Avoid busy waiting
  • In a multitasking system we would want to avoid
    having any processes use the busy waiting
    strategy whenever possible, as it stalls any
    progress by other tasks its a
    system-performance bottleneck!
  • So modern operating systems support an
    alternative strategy, which allows those tasks
    that could proceed to do so

6
blocking while idle
  • If a task is trying to read from a device-file
    when no data is present, but new data is expected
    to arrive, the operating system can block that
    task from consuming any valuable CPU time while
    it is waiting, by putting the task to sleep
    yet arranging for that task to be awakened as
    soon as some fresh data has actually arrived

7
blocking while busy
  • Similarly, if a task is trying to write to a
    device-file, but that device is busy with
    previously written data, then the OS can put this
    task to sleep, preventing it from wasting any CPU
    time during its delay so that other tasks can do
    useful work but arranging for this sleeping
    task to be woken up as soon as the device is no
    longer busy and can accept fresh data

8
What does sleep mean?
  • The Linux kernel puts a task to sleep by simply
    modifying the value of its state variable
  • TASK_RUNNING
  • TASK_STOPPED
  • TASK_UNINTERRUPTIBLE
  • TASK_INTERRUPTIBLE
  • Only tasks with state TASK_RUNNING are
    granted time on the CPU by the scheduler

9
What does wakeup mean?
  • A sleeping task is one whose task.state is
    equal to TASK_INTERRUPTIBLE or to
    TASK_UNINTERRUPTIBLE
  • A sleeping task is woken up by changing its
    task,state to be TASK_RUNNING
  • When the Linux scheduler sees that a task is in
    the TASK_RUNNING state, it grants that task
    some CPU time for execution

10
run queues and wait queues
  • In order for Linux to efficiently manage the
    scheduling of its various tasks, separate
    queues are maintained for running tasks and for
    tasks that temporarily are blocked while
    waiting for a particular event to occur (such as
    the arrival of new data from the keyboard, or the
    exhaustion of prior data sent to the printer)

11
Some tasks are ready-to-run
Those tasks that are ready-to-run comprise a
sub-list of all the tasks, and they are arranged
on a queue known as the run-queue Those
tasks that are blocked while awaiting a specific
event to occur are put on alternative sub-lists,
called wait queues, associated with the
particular event(s) that will allow a blocked
task to be unblocked
12
Kernel waitqueues
waitqueue
waitqueue
waitqueue
waitqueue
13
Kernels support-routines
  • The Linux kernel makes it easy for drivers to
    perform the sleep and wakeup actions while
    avoiding potential race conditions that are
    inherent in a preemptive kernel
  • Your driver can use the support-routines by
    including the header

14
Use of Linux wait-queues
  • include
  • wait_queue_head_t my_queue
  • init_waitqueue_head( my_queue )
  • sleep_on( my_queue )
  • wake_up( my_queue )
  • But cant unload driver if task stays asleep!

15
interruptible is preferred
  • include
  • wait_queue_head_t wq
  • init_waitqueue_head( wq )
  • wait_event_interruptible( wq, )
  • wake_up_interruptible( wq )
  • An interruptible sleep can be awoken by a
    signal,
  • in case you might want to unload your driver!

16
A convenient macro
  • DECLARE_WAIT_QUEUE_HEAD( wq )
  • This statement can be placed outside your
  • modules functions (i.e., a global object)
  • It combines declaration with initialization
  • wait_queue_head_t wq
  • init_waitqueue_head( wq )

17
Our stash device
  • Device works like a public clipboard
  • It uses kernel memory to store its data
  • It allows communication between tasks
  • What one task writes, another can read!

18
Ringbuffer
  • A first-in first-out data-structure (FIFO)
  • Uses a storage array of finite length
  • Uses two array-indices head and tail
  • Data is added at the current tail position
  • Data is removed from the head position

19
ringbuffer depicted
HEAD
D A T A
D A T A
D A T A
D A T A
D A T A
TAIL
FIFO rules The next data to be added goes
in at the current tail position, and the next
data to be removed comes from the head
position The ringbuffer is empty when
head equals tail, and it is full
if tail 1 equals head (modulo RINGSIZE)
20
Ringbuffer (continued)
  • One array-position is always left unused
  • Condition head tail means empty
  • Condition tail head-1 means full
  • Both head and tail will wraparound
  • Calculation next ( next1 )RINGSIZE

21
read-algorithm for stash
  • if ( ringbuffer_is_empty )
  • // sleep, until another task supplies some data
  • // or else exit if a signal is received by this
    task
  • Remove a byte from the ringbuffer
  • Copy the byte to user-space
  • Awaken any sleeping writers
  • return 1

22
write-algorithm for stash
  • if ( ringbuffer_is_full )
  • // sleep, until some data is removed by another
    task
  • // or else exit if a signal is received by this
    task
  • Copy a byte from user-space
  • Insert this byte into ringbuffer
  • Awaken any sleeping readers
  • return 1

23
Demonstration of stash
  • Quick demo we can use I/O redirection
  • For demonstrating write to /dev/stash
  • echo Hello /dev/stash
  • For demonstrating read from /dev/stash
  • cat /dev/stash

24
The device file-node
  • We cannot use the stash.c device-driver until a
    device-node has been created that allows both
    read and write access (the SysAdmin must
    usually do this setup)
  • root mknod /dev/stash c 40 0
  • root chmod arw /dev/stash
  • But you can do it, by using a module that
    resembles our tempcdev.c demo (if you just
    modify its module-data appropriately)

25
In-class exercise 1
  • Download a fresh copy of our tempcdev.c module
    and edit it, so that it will create the
    /dev/stash device-file when you install it
  • Then you can try using our stash.c demo to send
    data from one task to another task by using the
    echo and cat commands

26
In-class exercise 2
  • Add a get_info() function to this driver to
    create a pseudo-file (named /proc/stash) that
    will show the current contents of the ringbuffer
    (if any) and the current values for the head
    and tail buffer-indices
  • Dont forget use create_proc_info_entry() in
    your init_module() function, and use
    remove_proc_entry() during cleanup
Write a Comment
User Comments (0)
About PowerShow.com