Kernel timing issues - PowerPoint PPT Presentation

About This Presentation
Title:

Kernel timing issues

Description:

... to sleep until a fixed amount of time has elapsed (as measured in jiffies) When the timer expires, a driver-defined action will be performed, which can ... – PowerPoint PPT presentation

Number of Views:58
Avg rating:3.0/5.0
Slides: 28
Provided by: professora5
Learn more at: https://www.cs.usfca.edu
Category:

less

Transcript and Presenter's Notes

Title: Kernel timing issues


1
Kernel timing issues
  • An introduction to the use of kernel timers and
    work queues

2
Kernel timers
  • Linux offers a facility that lets drivers put a
    process to sleep until a fixed amount of time has
    elapsed (as measured in jiffies)
  • When the timer expires, a driver-defined action
    will be performed, which can wake up the
    process that was put to sleep, or could perform
    some alternative action (for example, the kernel
    timer could re-start)

3
jiffies
  • unsigned long volatile jiffies
  • global kernel variable (used by scheduler)
  • initialized to zero when system reboots
  • gets incremented during a timer interrupt
  • so it counts clock-ticks since cpu restart
  • tick-frequency is a configuration option
  • On our machines HZ250 (in .config)

4
jiffies overflow
  • Wont overflow for at least 16 months
  • Linux kernel got modified to fix overflow
  • Now the declaration is in linux/jiffies.h
  • unsigned long long jiffies_64
  • and a new instruction in do_timer()
  • ((u64)jiffies_64)
  • which compiles to assembly language as
  • add 1, jiffies0
  • adc 0, jiffies4

5
Kernel timer syntax
  • Declare a timer struct timer_list mytimer
  • Initialize this timer init_timer( mytimer )
  • mytimer.func mytimeraction
  • mytimer.data (unsigned long)mydata
  • mytimer.expires ltnumber-of-jiffiesgt
  • Install this timer add_timer( mytimer )
  • Modify this timer mod_timer( mytimer, ltjifsgt
    )
  • Delete this timer del_timer( mytimer )
  • Delete it safely del_timer_sync( mytimer)

6
A kernel-timer caution
  • A kernel timers timeout-action cannot do
    anything that could cause the current task to
    sleep (such as copying data between user-space
    and kernel-space, or trying to allocate more
    kernel memory)
  • However, to aid debugging, a timer CAN use
    printk() within its timeout-routine

7
trytimer.c
  • We have posted an example that shows how a Linux
    kernel timer can be used to perform a periodic
    action (such as using printk() to issue a
    message every time the time expires, then restart
    the timer
  • Notice that our demo is not able to issue
    messages directly to the console its
    timer-function executes without a tty

8
Delaying work
  • If a device-driver needs to perform actions that
    require using process resources (like a tty), or
    that may possibly sleep, then it can defer that
    work using a workqueue

9
Programming syntax
  • Declare struct workqueue_struct myqueue
  • struct work_struct thework
  • Define void dowork( void data ) / actions
    /
  • Initialize myqueue create_singlethread_workqu
    eue( mywork )
  • INIT_WORK( thework, dowork, ltdata-pointergt )
  • Schedule queue_dalayed_work( myqueue,
    thework, ltdelaygt )
  • Cleanup if ( !cancel_delayed_work( thework ) )
  • flush_workqueue( myqueue )
  • destroy_workqueue( myqueue )

10
tryworkq.c and defermsg.c
  • We have posted demo-modules that show the use of
    workqueues to perform actions later, either as
    soon as a process context is available, or
    after a prescribed time
  • Further details on the options for using an
    existing kernel workqueue or a workqueue of your
    own creation may be found in our textbook
    (Chapter 7 of LDD3)

11
Applying these ideas
  • To demonstrate a programming situation in which
    using kernel timers is valuable, we created the
    foo.c device-driver, plus an application that
    uses it (watchfoo.cpp)
  • You can compile and install the module, then
    execute the application watchfoo
  • But you will notice there are two problems
    (excess cpu usage and loop-termination)

12
Reducing CPUs usage
  • The watchfoo program rereads /dev/foo
    constantly (numerous times per second), much
    faster than the human eye can see
  • If you run the top utility, you will see that a
    high percentage of the available CPU time is
    being consumed by watchfoo
  • You can add a kernel timer to the foo.c driver
    to curtail this excessive reading

13
In-class exercise
  • Modify foo.c (call it timedfoo.c) as follows
  • Create an integer flag-variable (ready) as a
    global object in your module
  • When your read() function gets called, it
    should sleep until ready equals TRUE it should
    set ready equal to FALSE when it awakens, but
    should set a timer to expire after 1/10 seconds
  • Your timers action-function should set ready
    back to TRUE, then wake up any sleeping tasks

14
Implementation hints
  • You need a wait-queue (so your drivers reader
    tasks can sleep on it)
  • You need a timer action-function
  • You need to organize your timer-functions
    data-items into a single structure (because the
    timer-function has only one argument)
  • Your timer-function must do two things
  • Change ready to TRUE
  • Wake up any sleepers

15
Deferring work
  • Linux supports a workqueue mechanism which
    allows the kernel to defer specified work until
    some later point in time
  • This mechanism has been reworked in a major way
    since our texts were published
  • So any device-driver has to be modified if it
    made any use of a kernel workqueue
  • Changes require grasp of some macros

16
sizeof and offsetof
  • Our GNU compilers permit use of these C/C
    operators on object types
  • The sizeof operator returns the number of bytes
    of memory the compiler allocated for storing the
    specified object
  • The offsetof operator returns the number of
    bytes in a structure which precede the specified
    structure-member

17
A struct example
struct mystruct char w short x long y
long long z my_instance
You can use the sizeof operator to find out how
much memory gets allocated to any struct
mystruct object, like this int nbytes
sizeof( my_instance ) You can use the
offsetof operator to find out where within a
given structure a particular field occurs, like
this int offset_z offsetof( struct mystruct,
z )
18
The container_of() macro
  • Recent versions of the Linux kernel have
    introduced a further operator on
    structs container_of( ptr, type, member )
  • When given a pointer to a field within a
    structure-object, and the type-name for that that
    structure-object, and the field-name for that
    structures field-member, then it returns the
    structures address

19
Using container_of()
struct mystruct char w short x long y
long long z my_instance 1, 2, 3, 4

If you have a pointer to one of the fields in
some instance of a this kind of struct object,
then you could use the container_of() macro to
get a pointer to that struct object itself,
like this long ptr
my_instance.y struct mystruct p
container_of( ptr, struct mystruct, y ) This
would be useful if you now wanted to access other
members printk( wd xd yd zd \n,
p-gtw, p-gtx, p-gty, p-gtz )
20
  • include ltlinux/workqueue.hgt
  • void dowork( struct work_struct data )
  • DECLARE_DELAYED_WORK( mywork, dowork )
  • struct workqueue_struct myqueue
  • myqueue create_singlethread_workqueue( mywork
    )

21
workqueue syntax
include ltlinux/workqueue.hgt struct
workqueue_struct myqueue // pointer to your
workqueue void dowork( struct work_struct data
) // your functions prototype DECLARE_DELAYED_WO
RK( mywork, dowork ) int init_module( void
) myqueue create_singlethread_workqueue(
mywork ) if ( !queue_delayed_work( myqueue,
mywork, HZ5 ) ) return EBUSY return 0 //
SUCCESS void cleanup_module( void
) destroy_workqueue( myqueue )
22
tryworkq.c
In this example the delayed work consists of
simply printing a message to the kernels
logfile -- you can view by typing the dmesg
command
void dowork( struct work_struct data
) printk( \n\n I am doing the delayed work
right now \n )
Notice that the action function in this example
ignores its data argument
23
An improved example
  • Our announce.c module shows how an LKM could
    display its messages within a window on the Linux
    graphical desktop
  • It uses the tty_struct object which exists in
    the process-descriptor for the insmod task
    which you launch to install the LKM
  • We shall see how this same idea can be used in a
    waitqueues action functions

24
timer verses workqueue
  • Any kernel-timers action-function will be
    executed in atomic context just like an
    interrupt service routine it cannot sleep, and
    it cannot access any user-space data
  • But any workqueues action-function will be
    executed by a kernel-thread and thus it
    possesses a process context, so it can be
    scheduled and sleep if necessary though it,
    too, cannot access user-space

25
If dowork() needs data
// data items needed by your dowork function
are packaged in a struct struct
mydata char msg struct
tty_struct tty my_data \nHello\n,
NULL // your module-initialization function
sets up your struct delayed_work object // and
it can also finish initializing your my_data
objects member-fields myqueue
create_singlethread_workqueue( mywork
) INIT_DELAYED_WORK( mywork, dowork
) my_data.tty current-gtsignal-gttty // then
your action-function can access members of your
my_data object like this void dowork( struct
work_struct data ) struct mydata dp
container_of( my_data.msg, struct mydata, msg
) struct tty_struct tty dp-gttty tty-gtdriver
-gtwrite( tty, dp-gtmsg, strlen( dp-gtmsg ) )
26
defermsg.c
  • This LKM will display a message within a desktop
    window after a 10-second delay
  • It illustrates a use of the container_of()
    macro (as is needed by the reworked API for the
    Linux kernels workqueues)
  • Our course-website has a link to an online
    article by author Jonathan Corbet giving details
    of ongoing kernel changes in 2.6

27
Summary of tonights demos
  • foo.c and watchfoo.cpp
  • announce.c
  • trytimer.c
  • trymacro.c
  • tryworkq.c
  • defermsg.c
  • EXERCISE Modify the foo.c device-driver to use
    a kernel timer in its read() method
Write a Comment
User Comments (0)
About PowerShow.com