task_struct 线程节点

task_struct node for threads

很抱歉,如果我重复了别人多次问过的同一个问题,但我找不到满意的答案。因此,再次发布这个简单的查询。

问题:据我了解,Linux中的每个线程在内核任务link列表中都有一个'task_struct'节点。

Linux Version : 
#lsb_release -a
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.3 LTS
Release:    20.04
Codename:   focal

我写了一个 linux 内核模块来遍历 'task_struct' 的完整列表,并找出哪些 'task_struct' 节点属于我的简单程序(它有一个主线程和使用 pthread_create() 函数创建了 4 个线程,总共 5 个线程)。

下面是我的模块的核心逻辑,用于找出列表中属于特定 'tgid'(线程组 ID)的所有 'task_struct' 成员。 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);

下面是 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

编译并加载它:

#make
#insmode mymodule.ko

在内核中插入这个模块后,我为 tgid 传递了一个参数,如下所示。

echo 7196 > /sys/module/mymodule/parameters/arg

'7196' 是一个用户程序的 pid,它总共有 5 个线程(如前所述)。 在这里,我希望我应该得到'task_struct'的5个条目,但实际上它只显示一个,如下所示:

#dmesg | tail
[ 4432.971557] task_struct node : 000000007bede576   Name: a.out     PID:[7196]  TGID:[7196]     State:TASK_RUNNING

请帮助我理解这种行为,就线程在 Linux 中的表示方式而言,我的理解可能是错误的。

我的理解是,Linux所有的执行程序都以线程的形式存在,有些线程共享内存区域(也有相同的'tgid'(线程组id,称为相同的线程过程)).

进程和线程都使用struct task_struct,但是你需要两个嵌套循环来遍历所有线程。外循环遍历进程,内循环遍历该进程的线程。

例如:

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();
}