Linux内核API __task_pid_nr_ns

__task_pid_nr_ns 此函数获取进程的进程号,此进程应满足如下约束条件:

1)如果参数type不等于PIDTYPE_PID,则参数task用其所属任务组中的第一个任务赋值,否则保持task不变。

2)此进程是参数task任务描述符中的进程。

3)保证进程描述符的pid_namespace和参数ns相同。

__task_pid_nr_ns文件包含

#include <linux/sched.h>

__task_pid_nr_ns函数定义

在内核源码中的位置: linux-3.19.3/kernel/pid.c

函数定义格式:

pid_t __task_pid_nr_ns(struct task_struct *task, enum pid_type type, struct pid_namespace *ns)

__task_pid_nr_ns输入参数说明

  • 参数task是struct * task_struct型变量,保存任务的基本信息,其定义在文件linux-3.19.3/include/linux/sched.h中,内核源码注释比较详细,请读者自行查看。
  • 参数type是pid_type型变量,此变量是一个枚举型变量,见文件linux-3.19.3/include/linux/pid.h,其定义如下:
enum pid_type
{
    PIDTYPE_PID,           //进程的进程号
    PIDTYPE_PGID,          //进程组领头进程的进程号
    PIDTYPE_SID,           //会话领头进程的进程号
    PIDTYPE_MAX
};
  • 参数ns是struct pid_namespace型变量,是对进程命名空间信息的描述,见文件linux-3.19.3/include/linux/pid_namespace.h,其定义如下:
struct pid_namespace {
    struct kref kref;
    struct pidmap pidmap[PIDMAP_ENTRIES];
    struct rcu_head rcu;
    int last_pid;
    unsigned int nr_hashed;
    struct task_struct *child_reaper;
    struct kmem_cache *pid_cachep;
    unsigned int level;
    struct pid_namespace *parent;
#ifdef CONFIG_PROC_FS
    struct vfsmount *proc_mnt;
    struct dentry *proc_self;
    struct dentry *proc_thread_self;
#endif
#ifdef CONFIG_BSD_PROCESS_ACCT
    struct bsd_acct_struct *bacct;
#endif
    struct user_namespace *user_ns;
    struct work_struct proc_work;
    kgid_t pid_gid;
    int hide_pid;
    int reboot;   /* 如果pidns被重启,则执行进程组退出代码 */
    struct ns_common ns;
};

其中:

  • 字段kref是一个引用计数器,代表此命名空间在多少进程中被使用。
  • 字段pidmap[]记录当前系统的PID使用情况。
  • 字段last_pid记录上一次分配给进程的PID值。
  • 字段child_reaper保存了指向该进程的task_struct的指针。
  • 字段pid_cachep指向该进程在Cache中分配的空间。
  • 字段parent是指向父命名空间的指针。

字段level表示当前命名空间在命名空间层次结构中的深度,初始命名空间的level为0,该命名空间的子空间level为1,下一层的子空间level为2,以此类推。level的计算比较重要,因为level较高的命名空间中的ID,对level较低的命名空间来说是可见的,通过给定的level设置,内核即可推断进程会关联到多少个ID。

__task_pid_nr_ns返回参数说明

此函数的返回结果是符合条件的进程的进程号。

__task_pid_nr_ns实例解析

编写测试文件:__task_pid_nr_ns.c

头文件引用:

#include <linux/module.h>
#include <linux/sched.h>
#include <linux/pid.h>
MODULE_LICENSE("GPL");

模块加载函数定义:

static int __init __task_pid_nr_ns_init(void)
{
    printk("into __task_pid_nr_ns_init.\n");

    //获取当前进程的进程描述符,current为struct task_struct类型变量,记录当前进程的信息
    struct pid * kpid=find_get_pid(current->pid);

    // 获取进程所属任务的任务描述符
    struct task_struct * task=pid_task(kpid, PIDTYPE_PID);

    // 获取任务对应进程的进程描述符
    pid_t result1=__task_pid_nr_ns(task, PIDTYPE_PID, kpid->numbers[kpid->level].ns);

    //显示函数find_get_pid( )返回值的进程描述符的进程号
    printk("the pid of the find_get_pid is :%d\n", kpid->numbers[kpid->level].nr);

    //显示函数__task_pid_nr_ns( )的返回值
    printk("the result of the __task_pid_nr_ns is:%d\n", result1);
    printk("the pid of current thread is :%d\n", current->pid);  //显示当前进程号
    printk("out __task_pid_nr_ns_init.\n");
    return 0;
}

模块退出函数定义:

static void __exit __task_pid_nr_ns_exit(void)
{
    printk("Goodbye __task_pid_nr_ns\n");
}

模块加载和退出函数调用:

module_init(__task_pid_nr_ns_init);
module_exit(__task_pid_nr_ns_exit);

实例运行结果及分析:

首先编译模块,执行命令insmod __task_pid_nr_ns.ko插入模块,然后执行命令dmesg -c,会出现如图所示的结果。
Linux内核API __task_pid_nr_ns

结果分析:

由上图可以看出函数__task_pid_nr_ns( )能够获得与输入参数相对应的进程的进程号,当前进程的进程号是8634。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程