Kernel timing issues

cs.albany.edu
  • No tags were found...

Kernel timing issues

Summary of tonight’s demos• ‘foo.c’ and ‘watchfoo.cpp’• ‘trytimer.c’• ‘tryworkq.c’• ‘announce.c’ YOU MUST FIX!!• ‘defermsg.c’ YOU MUST FIX!!• EXERCISE1: Modify the ‘foo.c’ device-driver touse in its ‘read()’ method thewait_event_interruptible_timeoutfunction to sleep on a kernel timer• EXERCISE2: Do the same except use an eventqueue, an explicit kernel timer and thewait_event_interruptible/wake_up_interruptiblefunctions.


jiffies overflow• Won’t 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 asaddadc$1, jiffies+0$0, jiffies+4


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 = • Install this timer: add_timer( &mytimer );• Modify this timer: mod_timer( &mytimer, );• Delete this timer: del_timer( &mytimer );• Delete it safely: del_timer_sync( &mytimer);(2)what header files/.c filesdeclare/define the above structureand functions?_______________


A kernel-timer caution• A kernel timer’s timeout-action cannot doanything that could cause the current taskto ‘sleep’ (such as copying data betweenuser-space and kernel-space, or trying toallocate more kernel memory)• However, to aid debugging, a timer CANuse ‘printk()’ within its timeout-routine


‘trytimer.c’• We have posted an example that showshow a Linux kernel timer can be used toperform a periodic action (such as using‘printk()’ to issue a message every timethe time expires, then restart the timer• Notice that our demo is not able to issuemessages directly to the console – itstimer-function executes without a ‘tty’(3)What .h file defines struct timer_list?______ Whatare the types of expires? data? function?(4) How did YOU observe the output?____________


Displaying stuff to a terminal• Cruise's announce.c demo shows how toaccess the tty device belonging to aprocess so to write messages to theterminal window of the process.• Unfortunately, the tty device interfacechanged since then, so a (minor) part ofthis lab is to track down the data structuresrelated to tty devices and FIX THE BUG!• But read about other delay facilities first.


Delaying work• If a device-driver needs to perform actionsthat require using process resources (likea tty), or that may possibly ‘sleep’, then itcan defer that work – using a ‘workqueue’


Programming syntax• Declare: struct workqueue_struct *myqueue;struct work_struct thework;• Define: void dowork( void *data ) { /* actions */ };• Initialize: myqueue = create_singlethread_workqueue( “mywork” );INIT_WORK( &thework, dowork, );• Schedule: queue_dalayed_work( myqueue, &thework, );• Cleanup: if ( !cancel_delayed_work( &thework ) )flush_workqueue( myqueue );destroy_workqueue( myqueue );(5) What header files or .c files define each of thefunctions and structure types used in theprogramming syntax? They are used in trywork.c


‘tryworkq.c’ and ‘defermsg.c’• We have posted demo-modules that showthe use of workqueues to perform actionslater, either as soon as a ‘process context’is available, or after a prescribed time• Further details on the options for using anexisting kernel workqueue or a workqueueof your own creation may be found in ourtextbook (Chapter 7 of LDD3)http://lwn.net/images/pdf/LDD3/(6)What header or .c files define the types and functionsused in defermsg? (7) FIX defermsg.c so it works onyour virtual machine's linux version!


Applying these ideas• To demonstrate a programming situationin which using kernel timers is valuable,we created the ‘foo.c’ device-driver, plusan 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 looptermination)


Reducing CPU’s 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 thata high percentage of the available CPUtime is being consumed by ‘watchfoo’• You can add a kernel timer to the ‘foo.c’driver to curtail this excessive reading


Exercise 1:The Easy Way• Read about wait_event_interruptible_timeouton p194 and p209 of the Linux DeviceDrivers book handout.• Find out how to declare and initialize a waitqueue. Hint: Treasure hunt forwait_queue_head_t• Make the read() method sleep for 1 or 0.1second before reading the jiffies count.


Cruise's exercise2:• Modify ‘foo.c’ (call it ‘timedfoo.c’) as follows• Create an integer flag-variable (‘ready’) as aglobal object in your module• When your ‘read()’ function gets called, it shouldsleep until ‘ready’ equals TRUE; it should set‘ready’ equal to FALSE when it awakens, butshould set a timer to expire after 1/10 seconds• Your timer’s action-function should set ‘ready’back to TRUE, then wake up any sleeping tasks• This reviews the interrupt mode control logic sdccovered in the 500 course: See ULK excerpt.


Implementation hints• You need a wait-queue (so your driver’s‘reader’ tasks can sleep on it)• You need a timer action-function• You need to organize your timer-function’sdata-items into a single structure (becausethe timer-function has only one argument)[or, just use a global 'ready' flag andwait_queue. -sdc]• Your timer-function must do two things:– Change ‘ready’ to TRUE– Wake up any ‘sleepers’


Deferring work• Linux supports a ‘workqueue’ mechanismwhich allows the kernel to defer specifiedwork until some later point in time• This mechanism has been ‘reworked’ in amajor way since our texts were published• So any device-driver has to be modified ifit made any use of a kernel ‘workqueue’• Changes require grasp of some ‘macros’


Using a workqueue• #include • void dowork( struct work_struct *data );• DECLARE_DELAYED_WORK( mywork,dowork );• struct workqueue_struct *myqueue;• myqueue =create_singlethread_workqueue( “mywork” );


‘workqueue’ syntax#include struct workqueue_struct *myqueue; // pointer to your workqueuevoid dowork( struct work_struct *data ); // your function’s prototypeDECLARE_DELAYED_WORK( mywork, dowork );int init_module( void ){myqueue = create_singlethread_workqueue( “mywork” );if ( !queue_delayed_work( myqueue, &mywork, HZ*5 ) )return –EBUSY;return 0; // SUCCESS}void cleanup_module( void ){destroy_workqueue( myqueue );}


‘tryworkq.c’In this example the delayed work consists of simply printing a messageto the kernel’s logfile -- you can view by typing the ‘dmesg’ commandvoid 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


An improved example• Our ‘announce.c’ module shows how anLKM could display its messages within awindow on the Linux graphical desktop• It uses the ‘tty_struct’ object which existsin the process-descriptor for the ‘insmod’task which you launch to install the LKM• We shall see how this same idea can beused in a waitqueue’s ‘action’ functions


‘timer’ verses ‘workqueue’• Any kernel-timer’s action-function will beexecuted in ‘atomic’ context – just like aninterrupt service routine: it cannot ‘sleep’,and it cannot access any user-space data• But any workqueue’s action-function willbe executed by a kernel-thread – and thusit possesses a ‘process’ context, so it canbe ‘scheduled’ and ‘sleep’ if necessary –though it, too, cannot access user-space


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’ object’s member-fieldsmyqueue = create_singlethread_workqueue( “mywork” );INIT_DELAYED_WORK( &mywork, dowork );my_data.tty = current->signal->tty;// then your action-function can access members of your ‘my_data’ object like thisvoid dowork( struct work_struct *data ){struct mydata *dp = container_of( &my_data.msg, struct mydata, msg );struct tty_struct *tty = dp->tty;tty->driver->write( tty, dp->msg, strlen( dp->msg ) );}


‘defermsg.c’• This LKM will display a message within adesktop window after a 10-second delay• It illustrates a use of the ‘container_of()’macro (as is needed by the reworked APIfor the Linux kernel’s workqueues)• Our course-website has a link to an onlinearticle by author Jonathan Corbet givingdetails of ongoing kernel changes in 2.6


Original Summary• ‘foo.c’ and ‘watchfoo.cpp’• ‘announce.c’• ‘trytimer.c’• ‘trymacro.c’ (omitted for CSI500/400-alreadydone in a team report class!)• ‘tryworkq.c’• ‘defermsg.c’• EXERCISE: Modify the ‘foo.c’ device-driver touse a kernel timer in it’s ‘read()’ method


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 thiskind of ‘struct’ object, then you could use the ‘container_of()’ macroto 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( “w=%d x=%d y=%d z=%d \n”, p->w, p->x, p->y, p->z );


‘sizeof’ and ‘offsetof’• Our GNU compilers permit use of these C/C++ operators on object types• The ‘sizeof’ operator returns the number ofbytes of memory the compiler allocated forstoring the specified object• The ‘offsetof’ operator returns the numberof bytes in a structure which precede thespecified structure-member


A ‘struct’ examplestruct mystruct {char w;short x;long y;long long z;} my_instance;You can use the ‘sizeof’ operator to find out how much memory getsallocated to any ‘struct mystruct’ object, like this:int nbytes = sizeof( my_instance );You can use the ‘offsetof’’ operator to find out where within a givenstructure a particular field occurs, like this:int offset_z = offsetof( struct mystruct, z );


The ‘container_of()’ macro• Recent versions of the Linux kernel haveintroduced a further operator on ‘structs’container_of( ptr, type, member );• When given a pointer to a field within astructure-object, and the type-name forthat that structure-object, and the fieldnamefor that structure’s field-member,then it returns the structure’s address

More magazines by this user
Similar magazines