Pages

Tasklets -3 Using Macros


In the last two posts we learnt about the tasklets and creating them dynmically using taslet_init.
In this post let us look at an example module that will create a tasklet using the macros
DECLARE_TASKLET and DECLARE_TASKLET_DISABLED.

We use the macros as follows

DECLARE_TASKLET_DISABLED(task_dis,task_fn, 1);
task_dis is the name of the tasklet, task_fn is the function to be executed as part of the tasklet and we are passing "1" as data to the function. By default this tasklet will be disabled and will need to be enabled.


DECLARE_TASKLET(task_en,task_fn, 2); 
task_en is the name of the tasklet, task_fn is the function to be executed as part of the tasklet and we are passing "2" as data to the function.  By default the tasklet will be enabled and only needs to be scheduled.

We create two proc entries,

enabtask: To enable the tasklet that has started out disabled. We will print the value of the count to see the difference between the two tasklets .
schedtask: To schedule the tasklets that have been enabled. You can not schedule a tasklet that has not been enabled.

The proc entry function will look as follows



int enabtask(char *buf,char **start,off_t offset,int len,int *eof,void *arg)
{




printk(KERN_INFO " In proc enabtask");
printk(KERN_INFO "\n The state of disabled task is %d and count is  %d ",task_dis.state,task_dis.count);
printk(KERN_INFO "\n The state of enabled  task is %d and count is %d ",task_en.state,task_en.count);
tasklet_enable(&task_dis);


return 0;
}






int schedtask(char *buf,char **start,off_t offset,int len,int *eof,void *arg)
{
printk(KERN_INFO " In proc schedtask");
tasklet_schedule(&task_dis); 
tasklet_schedule(&task_en); 
printk(KERN_INFO "\n The state of disabled task is %d and count is  %d ",task_dis.state,task_dis.count);
printk(KERN_INFO "\n The state of enabled  task is %d and count is %d ",task_en.state,task_en.count);


return 0;
}

Note: To learn more about proc entries please see "Proc Entries" in  this page "Kernel Programming"



In the task_fn, which will be executed as part of the tasklet we will also print the data that has been passed to differentiated between the tasklets.


void task_fn(unsigned long arg)
{
printk(KERN_INFO "In tasklet function %u" ,arg);
}


The init and exit functions are similar to the previous example


int st_init(void)



create_proc_read_entry("enabask",0,NULL,enabtask,NULL);
create_proc_read_entry("schedtask",0,NULL,schedtask,NULL);


return 0;
}
void st_exit(void)
{
remove_proc_entry("enabask",NULL);
remove_proc_entry("schedtask",NULL);
}


Putting the code together the module will look as follows


************************tasklet_macro.c****************************
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/init.h>
#include<linux/proc_fs.h>
#include<linux/sched.h> 
#include <linux/interrupt.h>




void task_fn(unsigned long arg)
{
printk(KERN_INFO "In tasklet function %u" ,arg);
}
DECLARE_TASKLET_DISABLED(task_dis,task_fn, 1);
DECLARE_TASKLET(task_en,task_fn, 2);




int enabtask(char *buf,char **start,off_t offset,int len,int *eof,void *arg)
{




printk(KERN_INFO " In proc enabtask");
printk(KERN_INFO "\n The state of disabled task is %d and count is  %d ",task_dis.state,task_dis.count);
printk(KERN_INFO "\n The state of enabled  task is %d and count is %d ",task_en.state,task_en.count);
tasklet_enable(&task_dis);


return 0;
}


int schedtask(char *buf,char **start,off_t offset,int len,int *eof,void *arg)
{
printk(KERN_INFO " In proc schedtask");
tasklet_schedule(&task_dis); 
tasklet_schedule(&task_en); 
printk(KERN_INFO "\n The state of disabled task is %d and count is  %d ",task_dis.state,task_dis.count);
printk(KERN_INFO "\n The state of enabled  task is %d and count is %d ",task_en.state,task_en.count);


return 0;
}


int st_init(void)



create_proc_read_entry("enabask",0,NULL,enabtask,NULL);
create_proc_read_entry("schedtask",0,NULL,schedtask,NULL);


return 0;
}
void st_exit(void)
{
remove_proc_entry("enabask",NULL);
remove_proc_entry("schedtask",NULL);
}
module_init(st_init);
module_exit(st_exit);


*********************************************************************************

Save the code as tasklet_macro.c

Makefile needed for the module is

*************************Makefile*********************************
ifneq ($(KERNELRELEASE),) 
   obj-m := tasklet_macro.o
else 


KERNELDIR ?= /lib/modules/$(shell uname -r)/build 


PWD := $(shell pwd)


default: 
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules  
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
endif 
**************************************************************

To compile the test the code run as follows.

$ make 

If there are no errors, then continue.

$ insmod tasklet_macro.ko
$ cat /proc/enabtask
$ dmesg 


In proc enabtask

The state of disabled task is 0 and count is  1 


The state of enabled  task is 0 and count is 0 

You should see the above three lines of output in the log.
We can see that the state of both tasklets is 0 as neither of them are running .
The count value of disabled tasklet is "1" and that of enabled tasklet is "0".

$ cat /proc/schedtask

In proc schedtask


The state of disabled task is 1 and count is  0 
The state of enabled  task is 1 and count is 0 





In tasklet function 1
In tasklet function 2


From The above messaged we see tha the state of both the tasks have changed from 0 to 1 indicating that they are ready to and the count  of the tasks is 0 indicating that both are in enabled state.


The last two lines of the message prints the message present in task_fn and also prints the value of the data that we had passed to the respective tasklets.



No comments:

Post a Comment