Reputation: 10036
The following code loops over the ancestors of curr_task
, all the way to the swapper
process (i.e the "most distant" ancestor of any Linux process), where it stops because swapper == swapper->parent
.
while (curr_task != curr_task->parent)
...get curr_task info
curr_task = curr_task->parent
The problem is I also want to get the swapper
process's info. There are a couple obvious ways to do this (eg goto
statement after the while loop, or a single if
statement after the loop that gets the swapper
info). However, these obvious solutions seems fairly inelegant, and so I'm looking for a more concise solution that doesn't involve the much-maligned goto
or copy/pasting code.
Upvotes: 1
Views: 1877
Reputation: 11648
Use some functions to do it as follows.
walk_tasks_backwards_from(current);
Functions follow...
static void walk_tasks_backwards_from(struct task_struct *pos);
static void process_tasks(struct task_struct *parent, struct task_struct *child);
static void process_tasks(struct task_struct *parent, struct task_struct *child) {
pr_alert("parent process: %s, PID: %d\n", parent->comm, parent->pid);
pr_alert("child process: %s, PID: %d\n", child->comm , child->pid);
}
static void walk_tasks_backwards_from(struct task_struct *pos) {
struct task_struct *parent; ;
do {
parent = pos->parent;
process_tasks(parent, pos);
pos = parent;
} while(parent->pid != 0);
}
You call the function using current or any task you want to walk from ie
walk_tasks_backwards_from(current);
This produces the following output on my machine where I have a toy kernel module that I can trigger using cat /dev/toy
[161769.300609] parent process: bash, PID: 918
[161769.301299] child process: cat, PID: 2803
[161769.301973] parent process: login, PID: 626
[161769.302632] child process: bash, PID: 918
[161769.303216] parent process: systemd, PID: 1
[161769.303797] child process: login, PID: 626
[161769.304355] parent process: swapper/0, PID: 0
[161769.304978] child process: systemd, PID: 1
Alternatively you can use any of the following...
Use a do {} while
task = current;// Get current process
printk(KERN_INFO "process: %s, PID: %d", task->comm, task->pid);
do {
task = task->parent;
printk(KERN_INFO "process: %s, PID: %d", task->comm, task->pid);
} while (task->pid != 0);
//task here has pid == 0;
Or use a while loop.
task = current;// Get current process
while (task->pid != 0) {
printk(KERN_INFO "process: %s, PID: %d", task->comm, task->pid);
task = task->parent;
}
//task here has pid == 0;
printk(KERN_INFO "process: %s, PID: %d", task->comm, task->pid);
Loop over everything
struct task_struct task;
for_each_process(task) {
printk(KERN_INFO "process: %s, PID: %d", task->comm, task->pid);
}
Upvotes: 2
Reputation: 1062
In fact, we need RCU lock to protect us from crash:
void dump_current_ancestors(void)
{
struct task_struct *tmp;
printk("Comm PID TID\n");
rcu_read_lock();
tmp = current;
do {
printk("%s %d %d\n", tmp->comm, tmp->tgid, tmp->pid);
} while ((tmp != tmp->real_parent) && (tmp = tmp->real_parent));
rcu_read_unlock();
printk("-------end---------\n");
}`
Upvotes: 1
Reputation: 58172
Here's one way to do it: use another variable.
struct task_struct *t, *prev;
t = current;
do {
// do something with t
prev = t;
t = t->parent;
} while (prev->pid != 0);
Or move that into a function:
int move_up(struct task **tp) {
int was_swapper = ((*tp)->pid == 0);
*tp = (*tp)->parent;
return was_swapper;
}
// ...
struct task_struct *t = current;
do {
// do something with t
} while (move_up(&t));
Upvotes: 2