Thursday, September 22, 2011

Workqueue-3 using Runtime creation


In the last post we looked into creation of workqueue using static creation method. Let us look at creation using dynaminc creation i.e. using INIT_WORK.

The below call creates a workqueue by the name workq and the function that gets scheduled in the queue is work_fn.

INIT_WORK(workq,workq_fn)

But as this has to be done dynamically we will have to allocate memory  for the wrokqueue structure,before creating the workqueue, which can be done using kmalloc as below

workq = kmalloc(sizeof(struct work_struct),GFP_KERNEL); 

We can put these in the init function so that the workqueue gets crated as soon as the module is inserted.

In the work_fn  we will just add a print statement, but in real modules any thing can be scheduled in the function.

void workq_fn(unsigned long arg)


{
long c;
atomic_long_set(&(workq->data),10);
printk(KERN_INFO "In workq function %u",atomic_long_read(&(workq->data)));
}

Now to schedule the function we will implement the schedule function in the proc entry as
given below.

int sched_workq(char *buf,char **start,off_t offset,int len,int *eof,void *arg)
{
printk(KERN_INFO " In proc sched workq");
schedule_work(workq);


return 0;
}


The init function will have the calls to creation of proc entry and creation of the the workqueue.

int st_init(void)

create_proc_read_entry("sched_workq",0,NULL,sched_workq,NULL);
workq = kmalloc(sizeof(struct work_struct ),GFP_KERNEL);
INIT_WORK(workq,workq_fn);
return 0;


The exit function will only have removal of the proc entry
void st_exit(void)
{
remove_proc_entry("sched_workq",NULL);
}

Putting all the above together the module will look as follows



**********************workq_runtime.c*********************


#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/init.h>
#include<linux/proc_fs.h>  //Required for creating proc entries. 
#include<linux/sched.h> 
#include <linux/workqueue.h> // Required for workqueues


static struct work_struct *workq;




void workq_fn(unsigned long arg)
{
long c;
atomic_long_set(&(workq->data),10);
printk(KERN_INFO "In workq function %u",atomic_long_read(&(workq->data)));
}








int sched_workq(char *buf,char **start,off_t offset,int len,int *eof,void *arg)
{
printk(KERN_INFO " In proc sched workq");
schedule_work(workq);


return 0;
}


int st_init(void)

create_proc_read_entry("sched_workq",0,NULL,sched_workq,NULL);
workq = kmalloc(sizeof(struct work_struct ),GFP_KERNEL);
INIT_WORK(workq,workq_fn);
return 0;
}
void st_exit(void)
{
remove_proc_entry("sched_workq",NULL);
}
module_init(st_init);
module_exit(st_exit);
******************************************************

Save the above code as workq_runtime.c

The makefile required for compilation is

*****************Makefile**************************** 


ifneq ($(KERNELRELEASE),) 
   obj-m := workq_runtime.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 


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

Compile and run the code as follows

$ make 
If there are no errors then continued

$ insmod worq_runtime.ko
$ cat /proc/sched_work 
$ dmesg | tail -5 
In proc sched workq
In workq function 10

The above two lines inform us that once the proc entry is read, the function gets scheduled and if the processor is free it gets executed immediately .

Note : We have used a special function "atomi_set" to assign value to variable data in work_struct because the data is of type atomic_long_t and not simple int. 

0 comments:

Post a Comment