Pages

list_for_each and list_entry


The linux kernel provides a lot of macros to help us iterate through the list of processes running in the system.
The task_struct structure of all the processes running in the system are stored as a circular doubly linked list and there are number of macros/functions available which help us iterate through this list.

In this post we will look at the use of list_for_each and list_entry to iterate through the list. These two functions are generic functions for linked list in the kernel, we use them in this example to iterate through the list of proceeses.  These macros and functions are defined in linx/list.h

list_for_each("argument1","argument2") : Where argument1 is a temporary variable of type  "list_head" which will hold the current value of the list.
argument2 is agian a variable of type "list_head" but this is the head node of the list which has to be traversed.
list_head is the data type used when making use of the linked list provided in the kernel.

list_entry(ptr,type,member): This is macro uses the container_of() macro to return a pointer to the structure "type" that contains "member" which is of the type "ptr"

The code below creates a proc entry "ps_list". Which when read, lists out the siblings of the grandparent of the current process .

task = current->parent->parent   returns the grandparent of the current process which is assigned to "task"

list_for_each(list,&task->sibling): In this loop the siblings of "task" are repeatedly assigned to "list".

Each sibling will be located in its own task_stuct and to get the name of the sibling we need to know the address of the structure in which the sibling resides. Hence we used the "list_entry " macro as follows

task1=list_entry(list,struct task_struct,sibling); 

The above call, returns the pointer to the structure "task_struct" that contains the "sibling".

Once the pointer to task_struct is known, we can print the process  name and process id using
task1->comm and task1->pid.


**********************************************proc_list_entry.c***********************
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include<linux/sched.h>




int read_proc(char *buf,char **start,off_t offset,int count,int *eof,void *data ) 
{
int len=0;
struct task_struct *task, *task1;
struct list_head *list;
task = current->parent->parent;
printk(KERN_INFO "%s", task->comm);


list_for_each(list,&task->sibling) {


task1=list_entry(list,struct task_struct,sibling);
       len  += sprintf(buf+len, "\n %s %d \n",task1->comm,task1->pid);
  }


   
return len;
}


void create_new_proc_entry() 
{
create_proc_read_entry("ps_list",0,NULL,read_proc,NULL);


}




int functn_init (void) {
int ret;

create_new_proc_entry();
return 0;
}


void functn_cleanup(void) {
printk(KERN_INFO "In cleanup");
remove_proc_entry("ps_list",NULL);
}


MODULE_LICENSE("GPL");
module_init(functn_init);
module_exit(functn_cleanup);
******************************************************************************


**********************makefile*******************************************
KERNELDIR ?= /lib/modules/$(shell uname -r)/build 
obj-m := proc_list_entry.o
PWD := $(shell pwd)
all:
make -C $(KERNELDIR) M=$(PWD) modules
clean:
rm *.o *.mod.c *.order *.markers
********************************************************************

Run the following commands to see the output


$ make
$ sudo insmod proc_list_entry.ko 
$ cat /proc/ps_list 

You shuold be able to see a list of process names and their "pids".

You can verify the ouput by comparing it with the output of the command "pstree" which gives a tree structure output of all the processes
in the system.






1 comment:

  1. Dude, thanks so much. You have no idea how much this helped.

    Marry me.

    ReplyDelete