Search

Vi editor tips for programmers-1

A series of posts describing tips  helpful for programmers  who use VI editor. 


Finding matching braces in a program

The common error that comes across during programming in any language is mismatching braces. vi gives an easy way to track the matching
brace for each closing or opening brace.

For eg:

**********test.c**************

#include<stdio.h> 
main ()
{
printf("Hello world"); 


***************************
Open a vi editor and type the above program (or any program) into it and save it as test.c.

Move the cursor to the closing brace } and hit the % key. The cursur will auotmatically move to the corresponding openging brace .

Now try this one

*******************test.c******************
#include<stdio.h> 
main ()
{
printf("Hello world")); 

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

In the above program we have added an extra closing ")" bracket for the printf function call. Move the cursor to the second closing bracket and
hit "%". You will notice that the cursor does not move any where as it does not find the matching closing brace.

Let us look at one more example with a few more braces

******************test.c**********************
#include<stdio.h>
main ()
{
printf("Hello world");  
if(1) {
        printf("Hello again");
        }
else {
        printf("Hello once more");
        }
        }



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

Let us start by matching the opening brace this time. Move the cursor to first curly brace "{" and press "%". The cursor will move  to the closing brace "}" just above the final closing brace, which makes it obvious that one brace is extra in the code, thus we can remove the final curly brace to correct the program.

In the next post we will look at a few tips related to line numbers in the "vi" editor.
~

Difference between tasklet and workqueue


In the last few posts we saw the basics of tasklets and workqueues with examples. Both tasklet and workqueue are used for similar purposes, but they are not the same and can not be used instead of each other. Let us look at the differences between them.

This is biggest difference between the two  :

A tasklet always runs in the interrupt context, that means when a tasklet executes it is as if the processor is executing an interrupt service routine.
Thus while executing a tasklet a task can not got to sleep or can not hold a semaphore as neither of them are allowed while in a interrupt service routine.
On the other hand a workqueue executes as a normal process and not a interrupt, hence a worqueue can go to sleep it can hold semaphores.


The above difference will help in deciding when should a tasklet be used and when should a workqueue be used. To see this difference practically we will make use of a function "in_interrupt() ". When called, the function returns true if the task is executing as an interrupt i.e. in interrupt context else it returns false.

We will add this function call to the exaples of tasklet_init and workqueue_runtime and try to find out if tasklet runs in a interrupt context or not.

We only need to modify the tasklet and workqueue functions from the previous example and here are the modified functions

tasklet :  Modified task_fn

void task_fn(unsigned long arg)
{


printk(KERN_INFO "In tasklet function");
if(in_interrupt())
        printk(KERN_INFO "Running as an interrupt");
else
        printk(KERN_INFO "Running as a process");
printk(KERN_INFO "\n The state is %d",task->state);
printk(KERN_INFO "\n The count is %d",task->count);
}

workqueue: Modified work_fn

void workq_fn(unsigned long arg)
{


if(in_interrupt())
        printk(KERN_INFO "Running as an interrupt");
else
        printk(KERN_INFO "Running as a process");
atomic_long_set(&(workq->data),10);


printk(KERN_INFO "In workq function %u",atomic_long_read(&(workq->data)));
}



Modify the tasklet_init.c and workq_runtime.c as shown above. Compile and insert both the modules . If there are no errors in compiling and inserting
we can see the difference betwee the tasklet and worqueue as follows

$ cat /proc/initask
$ dmesg | tail -6
In proc initask
 In tasklet function
Running as an interrupt


 The state is 2

 The count is 0


$ cat /proc/sched_work
$ demsg | tail -4

In proc sched workq
Running as a processIn workq function 10


As we can see in the above output, when we run the tasklet we see that the task is running in the interrupt context and when we run the task in a workqueue it does not run as a interrupt but as a process.



Finding vendor id and product id of a usb device


Every usb device that we plug into a system has a vendo id and a product id that uniquely identifies the device. The vendor id is given by the usb.org to the vendor who in turn assigns unique product id to the products they manufacture. The kernel uses these product id and vendor id to find out if the driver supports the device or not.
To find the vendor id and product id of a device we can use the command "usb-devices" . The command lists out details of all the usb busses in the system and if any device is connected to any of the bus, it gives information of that device.

For eg:

$ usb-devices 

T:  Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=480 MxCh= 6
D:  Ver= 2.00 Cls=09(hub  ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=1d6b ProdID=0002 Rev=02.06
S:  Manufacturer=Linux 2.6.32-5-686 ehci_hcd
S:  Product=EHCI Host Controller
S:  SerialNumber=0000:00:02.2
C:  #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=0mA
I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub


T:  Bus=01 Lev=01 Prnt=01 Port=02 Cnt=01 Dev#=  2 Spd=480 MxCh= 0
D:  Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=0bc2 ProdID=5021 Rev=01.48
S:  Manufacturer=Seagate
S:  Product=FreeAgent GoFlex
S:  SerialNumber=NA01ZA6B
C:  #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA
I:  If#= 0 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage


T:  Bus=02 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12  MxCh= 3
D:  Ver= 1.10 Cls=09(hub  ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=1d6b ProdID=0001 Rev=02.06
S:  Manufacturer=Linux 2.6.32-5-686 ohci_hcd
S:  Product=OHCI Host Controller
S:  SerialNumber=0000:00:02.0
C:  #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=0mA
I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub


T:  Bus=03 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12  MxCh= 3
D:  Ver= 1.10 Cls=09(hub  ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=1d6b ProdID=0001 Rev=02.06
S:  Manufacturer=Linux 2.6.32-5-686 ohci_hcd
S:  Product=OHCI Host Controller
S:  SerialNumber=0000:00:02.1
C:  #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=0mA
I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub

The above output gives the information for Bus01,Bus02,Bus03.

If we observe the second set of output for Bus01 we can see that it gives us  details of a USB device whose manufacturer is Seagate. The product name is FreeAgent Goflex and the Vendor id is 0bc2 the product id is 5021. (The specific output is made into bold only for reference).

The other buses  do not have any device connected hence it only gives information of the bus, and the manufacturer by default is set to linux.

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. 

Workqueue-2 DECLARE_WORK


Last post we say the basics of workqueue and different ways to create a workqueue.
Let us now look at an example module to create a workqueue and schedule it.

We will create a workqueue using static creation , i.e. DECLARE_WORK and then look at the runtime creation in the next post.

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

DECLARE_WORK(workq,workq_fn); 

We will just add a print in the work_fn function but in real workqueues this function can be used to carry out any operations that need to be scheduled.

Our work_fn will look as follows
.
void workq_fn(unsigned long arg)
{
long c;
atomic_long_set(&(workq.data),10); //Setting the data field of work_struct. 
printk(KERN_INFO "In workq function %u",atomic_long_read(&(workq.data)));
}


For this function to be executed we need to schedule the workqueue which we will implement in a proc entry such that the workqueue gets scheduled when the proc entry is read.

Let us call the proc entry as sched_work, which will be as follows

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 and exit functions only need to create and remove the proc entries respectively.

int st_init(void)

create_proc_read_entry("sched_workq",0,NULL,sched_workq,NULL);
return 0;
}
void st_exit(void)
{
remove_proc_entry("sched_workq",NULL);
}

Putting all the codes together the module will be

*********************workq_static.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


void workq_fn(unsigned long); 


DECLARE_WORK(workq,workq_fn);
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);
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_stati.c . The makefile required for the compiling this will be

*************Makefile***************************
ifneq ($(KERNELRELEASE),) 
   obj-m := workq_static.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 test the code as follows

$ make 
If there are no errors then continued

$ insmod worq_static.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. 



Workqueues-1 Introduction


workqueues, like tasklets, are useful to schedule a task that for future. One of the
main areas where it is used is in scheduling the bottom half of an interrupt service routine.

One of the major differences between a tasklet and a workqueue, though both are used for similar purposes, is that a tasklet works in interrupt context where as a workqueue executes in a process context.
We will look into the differences between tasklet and workqueues in detail in another post.

In this post let us look at how to create a work queue and how to schedule it.
The work_queue are maintained in a structure work_struct, defined in workqueue.h.
The main members of the structure are

atomic_long_t data  : The data that will be used by the function that is scheduled by this workqueue.
work_func_t func : The function that has is scheduled by the workqueue.

The workqueues can be implemented in two ways
1. Using the default event threads  :The kernel provides default threads called event threads, one per processor, which can be used to schedule the deferred functions of the workqueues. This is simpler as we need not create a new thread and only need to queue up the function for execution. It is advantageous when the amount of work to be done by the deferred function is less
and is not a very strict constraints on the performance.
2. Creating a separate worker thread for the workqueue. Instead of using the default event threads, we can also create separate threads for the functions that have to be deferred as part of the workqueue. Generally separate worker threads are used only when amount of work the function to be deferred is huge which might affect the other workqueues scheduled on the default event thread.

Let us firs look at creating a workqueue using the default event thread.

Creation :

Static creation :
DECLARE_WORK(name, void (*func)(void *))
name: The name of the "work_struct" structure that has to be created.
func: The function to be scheduled in this workqueue.

Creating in runtime
INIT_WORK(struct work_struct *work, void (*func)(void *))

work: The work_struct structure that has to be created.
func: The function to be scheduled in this workqueue.

The prototype of function that has to be scheduled is
void func(void *data) 

As the workqueue executes in a process context this function is allowed sleep as well as use semaphores.

Scheduling
schedule_work(&work);

The work gets scheduled as soon as the above call to schedule_work is made, and the function gets executed when the events thread wakes up on the processor on which it is scheduled.

The scheduling can be delayed using the function
schedule_delayed_work(&work, delay);

Where the delay is mentioned in the timer ticks (jiffies).

Flushing all the works :

void flush_scheduled_work(void); 

The above call makes sure that all the functions that have been scheduled are executed and returns only after that. One of the applications of the function is while removing the module.
Before removing a module it should be made sure that all the functions deferred for execution by the module are finished which can be achieved by using the above function.

A workqueue can also be canceled using

int cancel_delayed_work(struct work_struct *work); 

The next post we will look at creation of workqueue using the static creation.

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.



Tasklet-2 using tasklet_init

In the previous post we saw the basics of a tasklet, now let us look at an example module that creates a tasklet.

We will use the function "tasklet_init" to create the tasklet in this example.

In this module we will create a read proc entry called "initask". On reading this proc entry a tasklet will get initialized and scheduled.

The function executed on reading the proc etnry will be :



Working :

task = kmalloc(sizeof(struct tasklet_struct),GFP_KERNEL);

This line allocates memory for a new tasklet and returns a pointer to the structure.

tasklet_init(task,task_fn,0);

This initates the tasklet "task" . The function that will be executed as a part of the tasklet is "task_fn" which has to be implemented in the module.

In our "task_fn" we will just print the state and value of count of the tasklet. In real tasklets, it is here that the main work happens.

task_fn:



The init and exit functions are going to be pretty simple as we have nothing much to do in them.

init and exit functions:

Thus the full code of the module with the required header files will look as follows tasklet_init.c

Save the code as tasklet_init.c

The Makefile required for this is



To see the output run the following commands



If there are no errors then continue.



Ouptut:

You shoud see the above lines being printed in the logs.

We scheduled the tasklet when proc entry was read, our processor was not heavily loaded hence the tasklet got scheduled immediately and thus the "task_fn" got executed.

The state "2" signifies the tasklet is running and the count being 0 signifies tasklet is enabled.

Tasklets -1 Introduction

Tasklets are used in kernel to schedule a function some time in future. The major use of the tasklet is to schedule the bottom half of an interrupt service routine.

Bottom half is the part of the interrupt service routine which is not time critical and can be executed after a little delay from the time interrupt is generated. This helps is releasing the interrupt line quickly and processing more interrupts.

Let us look at how we can create a tasklet and schedule it in a kernel module.

The structure, tasklet_struct, declared in interrupt.h looks as follows



The members of the structure that has to be initialized in the module are :

func : Pointer to the function that needs to scheduled for execution at a later time

data : Data to be passed to the function "func"

The other three members are initialized by the kernel as follows

"count" holds a nonzero value if the tasklet is disabled and 0 if it is enabled.

states

TASKLET_STATE_SCHED , which denotes it is scheduled to run. TASKLET_STATE_RUN , which denotes it is running.

There are two ways of creating a tasklet

Creating Statically: (using Macros)

DECLARE_TASKLET(name, func, data): Creates a tasklet in the enabled state

DECLARE_TASKLET_DISABLED(name, func, data): Creates a tasklet in the disabled state

If the tasklets is created using the second macro it needs to be enabled explicitly.

Creating in runtime:

tasklet_init(name,func,data)

Where "name" is the name of the taskelet, "func" in the function which has to be executed as a part of the tasklet and "data" is the data that has to passed to func.

Function:Prototype of the function that has to be scheduled by the tasklet is void "function"(unsigned long data)

A tasklet is a softirq and hence runs in an interrupt context. Thus while executing the function you are not allowed to go to sleep and have to use proper locking for any data that is shared with other tasklets.

Scheduling a tasklet:

Once the tasklet has been created, it needs to be scheduled which is done by the function

tasklet_schedule(&tasklet)

Enable and Disable :

The tasklets can be disabled, if they are not running already, using

tasklet_disable(&taskelt)

and enabled using

tasklet_enble(&tasklet)

When does the tasklet actually get scheduled can not be controlled and is decided by the scheduler depending on the load on the processor. If the processor is free, it might get scheduled immediately.

In the next two posts we will look at example code of creating tasklet statically and dynamically.

Tasklets-2 tasklet_init Tasklets-3 Using Macros

To kill a process after specific duration


If you want to make sure that a certain process or application runs exactly for a given duration and gets kill automatically after that, then the command timeout will help.

Let us say we want to run google-chrome for only a minute and then kill it, then we can do the following

$ timeout 1m google-chrome

1m specifies 1 minute, similarly you can use the suffix "s" for seconds and suffix "d" for days.
As a result of the above command, google-chrome will launch and will get killed automatically at the end of 1 minute from the time the command was run.

Enabling capslock from command line

setleds : Command to set the keyboard leds like capslock, numlock etc.

If you want to turn on the "capslock" or the "numlock" from the command line you can use this command.
For eg to turn on the caps lock run the following
Note: You will have to be in text mode to run the command,it does not run in graphics mode 

$ setleds +caps  


You should see the capslock led turn on and any thing you type will be in capital. You can turn the capital off by using the caps lock key on the keyboard but the led of caps lock will continue to glow.

To turn the led off run

$ setleds -caps

The same is valid for num lock using the keyword "num" and for scroll lock using the keyword "scroll".

Script to check for palindrome using "rev"

The command "rev" reverses the lines of the file given to it as input. we can use this command to find out whether a given string is palindrome or no.
A palindrome is any string that appears the same when read from left to right or right to left.
For Eg:
mom  : will be same if we read it left to right or right to left, hence it is a palindrome.
tree: will be read as eert if read from right to left which is different from tree hence the string is not a palindrome.

The command rev takes the lines of file given as input and prints them in reverse.
For eg:
If we have a file named "one" with contents  "The weather has been cloudy "

$ rev one 
yduolc neeb sah rehtaew ehT

As we see rev prints the line from right to left. 

Now let us try to write a script that will use "rev" to find out if a given string is a palindrome or not. 

Note: The script creates and new file by the name temp in the present working directory  and deletes it . In case you have any other file by the name temp, it will get overwritten and deleted if you do not rename it or modify the script.


#! /bin/bash 

if [ $# -le 2 ]            # if word is not passed in command line, take it as input. 
then 
echo "Enter the word"
read input                  # Store the word in variable input 
fi 
echo $input > temp         # Write the input into a temporary file. 
reverse=`rev temp`      # Run the command rev on the temporary file . store result in another variable 
echo $reverse              
if [ $input==$reverse ]  #Compare the input and reversed string. 
then
echo "it is a palindrome"         
else 
echo "Not a palindrome"
fi
rm temp           # Remove the temporary file created. 




Working directory of a process

If you want to find from which directory was a process launched or which directory is a process running from you can use the command "pwdx"
It takes as input the process id of the process of which you want to find the directory.

You will have to run the command as root. 


For eg:

$ sudo  pwdx 1 


The pid one belongs to "init"  and it is run from the root directory "/" .
You can use the command "ps -ef"  or "pidof"  to find the pid of the process you are interested in.