Linux进程管理之通过pid号找到struct task_struct

文章目录

  • 一、find_get_pid
    • 1.1 API详解
    • 1.2 API演示
  • 二、get_pid_task
    • 2.1 API详解
    • 2.2 API演示

一、find_get_pid

1.1 API详解

(1)
此函数根据用户层提供的进程号 nr 获取对应的进程描述符struct pid,并使进程描述符中的字段count的值加1,即此进程的用户数加1。

struct pid *find_get_pid(pid_t nr)
{
	struct pid *pid;

	rcu_read_lock();
	pid = get_pid(find_vpid(nr));
	rcu_read_unlock();

	return pid;
}
EXPORT_SYMBOL_GPL(find_get_pid);

(2)
将进程描述符 struct pid的count成员原子的+1。

static inline struct pid *get_pid(struct pid *pid)
{
	if (pid)
		atomic_inc(&pid->count);
	return pid;
}

(3)
根据提供的局部进程号获取对应的进程描述符 struct pid :
参数nr是进程对应的局部进程号,一般与进程号相同。
参数ns是struct pid_namespace型变量,是对进程命名空间信息的描述。

struct pid *find_pid_ns(int nr, struct pid_namespace *ns)
{
	struct upid *pnr;

	hlist_for_each_entry_rcu(pnr,
			&pid_hash[pid_hashfn(nr, ns)], pid_chain)
		if (pnr->nr == nr && pnr->ns == ns)
			return container_of(pnr, struct pid,
					numbers[ns->level]);

	return NULL;
}
EXPORT_SYMBOL_GPL(find_pid_ns);

// 参数nr是进程对应的局部进程号,一般与进程号相同。
struct pid *find_vpid(int nr)
{
	return find_pid_ns(nr, task_active_pid_ns(current));
}
EXPORT_SYMBOL_GPL(find_vpid);

1.2 API演示

我执行top命令,top的pid为44284。

#include 
#include 
#include 

static int __init find_get_pid_init(void)
{
    struct pid * kpid = find_get_pid(44284); //top的进程号:44284
    //struct pid * kpid=find_get_pid(current->pid); //根据进程号,调用函数获取进程描述符信息

    printk("the count of struct pid is :%d\n", kpid->count);    

    printk("the level of struct pid is :%d\n", kpid->level);

    printk("the upid of struct pid is :%d\n", kpid->numbers[kpid->level].nr);
  
    return -1;
}

module_init(find_get_pid_init);

MODULE_LICENSE("GPL");

二、get_pid_task

2.1 API详解

(1)struct task_struct
列举了struct task_struct的一些成员,接下来我将通过进程数值ID号,来获取struct task_struct,并打印这些成员。

struct task_struct {
	......
	volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
	atomic_t usage;
	pid_t pid;
	pid_t tgid;
	/* process credentials */
	char comm[TASK_COMM_LEN];  //不包括路径的可执行文件名称 
	......
}

其中成员 comm 使用 get_task_comm 访问(使用 task_lock() 锁定它),并 由 setup_new_exec 正常初始化

// linux-4.10.1/fs/exec.c
char *get_task_comm(char *buf, struct task_struct *tsk)
{
	/* buf must be at least sizeof(tsk->comm) in size */
	task_lock(tsk);
	strncpy(buf, tsk->comm, sizeof(tsk->comm));
	task_unlock(tsk);
	return buf;
}
EXPORT_SYMBOL_GPL(get_task_comm);

(2)get_pid_task
get_pid_task函数通过 struct pid 和 type 来获取进程的struct task_struct结构体。内部实现主要通过pid_task(pid, type)函数来获取struct task_struct结构体。

struct task_struct *get_pid_task(struct pid *pid, enum pid_type type)
{
	struct task_struct *result;
	rcu_read_lock();
	result = pid_task(pid, type);
	if (result)
		get_task_struct(result);
	rcu_read_unlock();
	return result;
}
EXPORT_SYMBOL_GPL(get_pid_task);

get_pid_task函数会将struct task_struct成员的usage变量加1。

备注:内核中函数带有get/put前缀的函数通常都会将引用计数+1或者-1。

#define get_task_struct(tsk) do { atomic_inc(&(tsk)->usage); } while(0)

(3)pid_task
pid_task这个函数是内核中用来获取struct task_struct的常用的辅助函数。用来获取pid->tasks[type]哈希表中的第一个task_struct实例。

struct task_struct *pid_task(struct pid *pid, enum pid_type type)
{
	struct task_struct *result = NULL;
	if (pid) {
		struct hlist_node *first;
	
		first = rcu_dereference_check(hlist_first_rcu(&pid->tasks[type]),
					      lockdep_tasklist_lock_is_held());
		if (first)
			result = hlist_entry(first, struct task_struct, pids[(type)].node);
	}
	return result;
}
EXPORT_SYMBOL(pid_task);

参数struct pid是内核对进程号的内部表示。
参数type是pid_type型变量,此变量是一个枚举型变量,定义如下:

enum pid_type
{
	PIDTYPE_PID,	//进程的进程号
	PIDTYPE_PGID,	//进程组领头进程的进程号
	PIDTYPE_SID,	//会话领头进程的进程号
	PIDTYPE_MAX		//表示进程号类型的数目 == 3
};

2.2 API演示

#include 
#include 
#include 
#include 
#include 

/* Module parameter */
static int pid = 0;
module_param(pid, int, 0);

//内核模块初始化函数
static int __init lkm_init(void)
{
    struct pid * kpid;
    struct task_struct *task;
    char task_name[TASK_COMM_LEN] = {0};

    kpid = find_get_pid(pid);
    task = get_pid_task(kpid, PIDTYPE_PID);

    printk("task name = %s , task pid = %d\n", get_task_comm(task_name, task), task->pid);

	return -1;
}

module_init(lkm_init);

MODULE_LICENSE("GPL");
[root@localhost get_task_by_pid]# insmod get_task_by_pid.ko pid=1
[root@localhost get_task_by_pid]# dmesg -c
[62943.164059] task name = systemd , task pid = 1

你可能感兴趣的:(Linux,进程管理,linux,c语言)