Issue
I am sorry if I am repeating the same query which has been asked by others so many times, but I could not find a satisfactory answer to this. Hence, posting this simply query again.
Question : As per my understanding, every thread in Linux has a 'task_struct' node in the kernel's task link list.
Linux Version :
#lsb_release -a
Distributor ID: Ubuntu
Description: Ubuntu 20.04.3 LTS
Release: 20.04
Codename: focal
I wrote a linux kernel module to go through the complete list of 'task_struct', and find out which 'task_struct' nodes belong to my simple program(which has one main thread and 4 created threads using pthread_create() function, total 5 threads).
Below is a the core logic of my module to find out all the 'task_struct' members of the list belong to a particular 'tgid' (thread group id). mymodule.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched/signal.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("MY_NAME");
MODULE_DESCRIPTION("Print a task details");
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:
return "UNKNOWN TYPE";
}
}
static void print_task_info(unsigned int tgid)
{
struct task_struct *task_list;
for_each_process(task_list) {
if (task_list->tgid == tgid) {
pr_info("task_struct node : %p\t Name: %s\t PID:[%d]\t TGID:[%d]\t State:%s\n",
task_list, task_list->comm, task_list->pid, task_list->tgid,
get_task_state(task_list->state));
}
}
return;
}
unsigned int arg;
static int notify_param(const char *val, const struct kernel_param *kp)
{
int res = param_set_int(val, kp);
pr_info("notify_param() called.\n");
if (!res) {
print_task_info(arg);
return 0;
}
return -1;
}
const struct kernel_param_ops my_module_param_ops =
{
.set = notify_param,
.get = param_get_int,
};
module_param_cb(arg, &my_module_param_ops, &arg, S_IRUSR|S_IWUSR);
static int __init my_module_init(void)
{
printk("Hello, Linux Kernel");
return 0;
}
static void __exit my_module_exit(void)
{
printk("Bye, Linux Kernel");
return;
}
module_init(my_module_init);
module_exit(my_module_exit);
Below is the Makefile:
obj-m += mymodule.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Compile and load it with :
#make
#insmode mymodule.ko
After inserting this module in kernel, I pass a parameter for tgid as below.
echo 7196 > /sys/module/mymodule/parameters/arg
The '7196' is the pid of a user program which has total 5 threads (as explained earlier). Here, I expect that I should have got 5 entries of 'task_struct', but actually it shows only one, as below:
#dmesg | tail
[ 4432.971557] task_struct node : 000000007bede576 Name: a.out PID:[7196] TGID:[7196] State:TASK_RUNNING
Kindly help me to understand this behaviour, as may be, my understanding is wrong in terms of how threads are represented in Linux.
My understanding is that, Linux has all executing programs in the form of threads, and some threads share memory regions(also has same 'tgid'(thread group id, called threads of the same process)).
Solution
Processes and threads both use struct task_struct
, but you need two nested loops to loop through all threads. The outer loop loops through processes and the inner loop loops through threads of that process.
For example:
static void print_task_info(unsigned int tgid)
{
struct task_struct *the_process;
struct task_struct *the_thread;
char comm[TASK_COMM_LEN];
rcu_read_lock();
for_each_process(the_process) {
if (task_tgid_nr(the_process) == tgid) {
for_each_thread(the_process, the_thread) {
pr_info("thread node: %p\t Name: %s\t PID:[%d]\t TGID:[%d]\n",
the_thread, get_task_comm(comm, the_thread),
task_pid_nr(the_thread), task_tgid_nr(the_thread));
}
break;
}
}
rcu_read_unlock();
}
Answered By - Ian Abbott Answer Checked By - Mildred Charles (WPSolving Admin)