Linux Kernel Driver to print all Processes:name,ID and its State
Linux kernel internally refers processes as tasks. Kernel stores the list of processes in a circular doubly linked list called the task list.
Each task/process is represented in kernel with struct task_struct (defined in <linux/sched.h>).
This data structure (task_struct) is huge (1.7 Kilobytes) containing all the information about a specific process.
Let's write a module/device driver which reads the circular linked list and prints the following information for us:
Each task/process is represented in kernel with struct task_struct (defined in <linux/sched.h>).
This data structure (task_struct) is huge (1.7 Kilobytes) containing all the information about a specific process.
Let's write a module/device driver which reads the circular linked list and prints the following information for us:
- Process Name
- Process ID
- Process State
Before that, we should know what are the different states a process can be:
- TASK_RUNNING: Process is either currently running or on a run-queue waiting to run
- TASK_INTERRUPTIBLE: Process is sleeping/blocked. Can be runnable/awaken by a signal
- TASK_UNINTERRUPTIBLE: Similar to TASK_INTERRUPTIBLE, but does not wakeup on a signal
- __TASK_TRACED: Process is traced by a debugger e.g. ptrace
- __TASK_STOPPED: Process execution has stopped. This happens when the task receives SIGSTOP, SIGTSTP, SIGTTIN or SIGTTOU signal or if it receives any signal while it is being debugged.
Code:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <linux/kernel.h> | |
#include <linux/module.h> | |
#include <linux/sched/signal.h> | |
char buffer[256]; | |
char * get_task_state(long state) | |
{ | |
switch (state) { | |
case TASK_RUNNING: | |
return "TASK_RUNNING"; | |
case TASK_INTERRUPTIBLE: | |
return "TASK_INTERRUPTIBLE"; | |
case TASK_UNINTERRUPTIBLE: | |
return "TASK_UNINTERRUPTIBLE"; | |
case __TASK_STOPPED: | |
return "__TASK_STOPPED"; | |
case __TASK_TRACED: | |
return "__TASK_TRACED"; | |
default: | |
{ | |
sprintf(buffer, "Unknown Type:%ld\n", state); | |
return buffer; | |
} | |
} | |
} | |
static int test_tasks_init(void) | |
{ | |
struct task_struct *task_list; | |
unsigned int process_count = 0; | |
pr_info("%s: In init\n", __func__); | |
for_each_process(task_list) { | |
pr_info("Process: %s\t PID:[%d]\t State:%s\n", | |
task_list->comm, task_list->pid, | |
get_task_state(task_list->state)); | |
process_count++; | |
} | |
pr_info("Number of processes:%u\n", process_count); | |
return 0; | |
} | |
static void test_tasks_exit(void) | |
{ | |
pr_info("%s: In exit\n", __func__); | |
} | |
MODULE_LICENSE("GPL"); | |
module_init(test_tasks_init); | |
module_exit(test_tasks_exit); |
O/P:
Notes:
1. init process is the parent of all the processes. So, it will be at the beginning of the circular linked list. Init task process descriptor is statically allocated.
extern struct task_struct init_task;
2. for_each_process is a macro which iterates over the entire task list. It is defined in <linux/sched/signal.h>
#define for_each_process(p) \
for (p = &init_task ; (p = next_task(p)) != &init_task ; )
Comments
Post a Comment