Friday, July 1, 2011

Changing process state in a module

The example shows how we can change the state of a process.

Every process in linux has a task_struct for itself which stores all the relevant information about the process.
The possible states a process can have in linux are

Running or Runnable defined as TASK_RUNNING
Interruptible sleep defined as TASK_INTERRUPTIBLE
Uniterruptible sleep defined as TASK_UNINTERRUPTIBLE
Terminated task defined as TASK_STOPPED
(There are few more states that are not used often).


To look at the state of the task we can use the command

ps -eo state,comm

For eg  : The ouput of the above command could be

S evince
S evinced
D gnome-terminal
S gnome-pty-helpe
S bash
R ps

The first column sigifies the state of the process where

S implies Interruptible Sleep 
D implies Uninterruptible Sleep
R implies Running or Runnable.    
T imples STOPPED


The second coulmn has the name of the process.



The module below creates a thread on inserting into the module kernel. The thread runs for a minute before terminating itself. The details how the thread gets created can be seen in "Kernel Threads" .

There are two proc entries that get created on inserting the module

suspend_state: On reading this proc entry the running thread's state is changed from running to Interruptible sleep
This is done by setting " thread1->state" to TASK_INTERRUPTIBLE. where thread1 is the task_struct of the thread that was created.

run_state: On reading this proc entry the thread that is in sleep state is woken up. This is done by calling wake_up_process() on thread1. Which reschedules the sleeping process.


You can read more about proc entry creation in "Creating proc entries" .

***************************process_change.c****************************************
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/semaphore.h>
#include <linux/kthread.h>  // for threads
#include <linux/sched.h>  // for task_struct
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/proc_fs.h>


/*char buffer[10];
int count;
struct semaphore sem;*/
static struct task_struct *thread1;



int thread_fn() {

unsigned long j0,j1;
int delay = 100*HZ;
j0 = jiffies;
j1 = j0 + delay;

while (time_before(jiffies, j1))
        schedule();
printk(KERN_INFO "In thread1");


set_current_state(TASK_INTERRUPTIBLE);
while (!kthread_should_stop())
{
   schedule();
   set_current_state(TASK_INTERRUPTIBLE);
}
set_current_state(TASK_RUNNING);

return 0;
}


int suspendstate(char *buf,char **start,off_t offset,int count,int *eof,void *data)
{
    printk(KERN_INFO "In suspend sate");
    thread1->state = TASK_INTERRUPTIBLE;
    return 0;
}

int runstate(char *buf,char **start,off_t offset,int count,int *eof,void *data)
{
    printk(KERN_INFO "In runsate");
     wake_up_process(thread1);   
    return 0;
}

int thread_init (void) {
   
    char name[15]="process1";
    printk(KERN_INFO "in init");
    thread1 = kthread_create(thread_fn,NULL,name);
    if((thread1))
        {
        printk(KERN_INFO "in if");
        wake_up_process(thread1);
        }
    create_proc_read_entry("suspend_state",0,NULL,suspendstate,NULL);
    create_proc_read_entry("run_state",0,NULL,runstate,NULL);
    return 0;
}



void thread_cleanup(void) {
    int ret;
    ret = kthread_stop(thread1);
    if(!ret)
        printk(KERN_INFO "Thread stopped");

}
MODULE_LICENSE("GPL");   
module_init(thread_init);
module_exit(thread_cleanup);
***************************************************************************************

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

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

PWD := $(shell pwd)

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

Save the above two files with the respective names and run the following commands to see the output.

$ make
$ sudo insmod process_change.ko
$ ps -eo state,comm | grep process1
R process1
The output shows process1 is currently running

$ cat /proc/suspend_state    
$ ps -eo state,comm | grep process1
S process1

After read of the proc entry suspend_state the process state changed to S, i.e. sleep state. But note the thread runs approximately for a minute so you will have to execute the "cat" command within one minute to be able to see this change.


$ cat /proc/run_state.
$ ps -eo state,comm | grep process1

R process1

After read of proc entry run_state the process state has again changed to run state.
To remove the module
$ sudo rmmod process_change



0 comments:

Post a Comment