Understanding The Getting of Task_Struct Pointer from Process Kernel Stack

Understanding the getting of task_struct pointer from process kernel stack

The kernel stack contains a special struct at the top -- thread_info:

 26 struct thread_info {
27 struct task_struct *task; /* main task structure */
28 struct exec_domain *exec_domain; /* execution domain */
29 __u32 flags; /* low level flags */
30 __u32 status; /* thread synchronous flags */
31 __u32 cpu; /* current CPU */
32 int preempt_count; /* 0 => preemptable,
33 <0 => BUG */
34 mm_segment_t addr_limit;
35 struct restart_block restart_block;
36 void __user *sysenter_return;
37 #ifdef CONFIG_X86_32
38 unsigned long previous_esp; /* ESP of the previous stack in
39 case of nested (IRQ) stacks
40 */
41 __u8 supervisor_stack[0];
42 #endif
43 unsigned int sig_on_uaccess_error:1;
44 unsigned int uaccess_err:1; /* uaccess failed */
45 };

So, to get the task_struct you'll need to get a thread_info pointer with GET_THREAD_INFO from the ASM-code:

183 /* how to get the thread information struct from ASM */
184 #define GET_THREAD_INFO(reg) \
185 movl $-THREAD_SIZE, reg; \
186 andl %esp, reg

... or with current_thread_info from the C-code:

174 /* how to get the thread information struct from C */
175 static inline struct thread_info *current_thread_info(void)
176 {
177 return (struct thread_info *)
178 (current_stack_pointer & ~(THREAD_SIZE - 1));
179 }

Note that THREAD_SIZE defined as (PAGE_SIZE << THREAD_SIZE_ORDER) and THREAD_SIZE_ORDER equals 1 for both x86_32 and x86_64 so THREAD_SIZE results to 8192 (2^13 or 1<<13).

How does the kernel use task_struct?

Yes, the task_struct structure contains all the information about a process. You can obtain a pointer to the structure that describes the current process using the current macro as follows:

struct task_struct *p = current;

If you want to get the structure that describes a process given a pid, you can use the find_task_by_vpid function as follows:

read_lock(&tasklist_lock);
p = find_task_by_vpid(pid);
if (p) get_task_struct(p);
read_unlock(&tasklist_lock);
if (p == NULL) {
// Task not found.
}

// Later, once you're finished with the task, execute:
put_task_struct(p);

Finally, if you want to iterate over all processes, you can use for_each_process as follows:

read_lock(&tasklist_lock);
for_each_process(p) {
// p is a pointer to a task_struct instance.
}
read_unlock(&tasklist_lock);

If you want to an exclusive access to the task list to be able to make changes to one or more fields in the structure, write_lock_irqsave must be used instead of read_lock.

kernel stack for linux process

There is just one common kernel memory. In it each process has it's own task_struct + kernel stack (by default 8K).

In a context switch the old stack pointer is saved somewhere and the actual stack pointer is made to point to the top of the stack (or bottom depending on the hardware architecture) of the new process which is going to run.

Linux Kernel task_struct void *stack

In Linux kernel source code you can see the macros task_thread_info():

#define task_thread_info(task)  ((struct thread_info *)(task)->stack)

The void *stack pointer of task_struct points to thread_info.

Since 2.6 version Linux uses part of a task's kernel-stack page-frame to store "thread information" (thread_info). The thread_info in its turn includes a pointer to the task_struct:

struct task_struct *task = info->task;

F.e. (for platforms where the stack grows in the direction of decreasing the value of the memory address):

Sample Image

Useful links: 1, 2


where are the pointers to the rest of the process image?

Such info is contained in memory descriptor mm_struct. F.e.:

struct mm_struct {
//...
unsigned long start_code, end_code, start_data, end_data;
unsigned long start_brk, brk, start_stack;
//...
}

Must-read: How The Kernel Manages Your Memory

How 'task_struct' is accessed via 'thread_info' in linux latest kernel?

Pointer to the current task_struct object is stored in architecture-dependent way. On x86 it is stored in per-CPU variable:

DECLARE_PER_CPU(struct task_struct *, current_task);

(In arch/x86/include/asm/current.h).

For find out how current task_struct is stored on particular architecture and/or in particular kernel version just search for implementation of current macro: exactly that macro is responsible for returning a pointer to the task_struct of the current process.



Related Topics



Leave a reply



Submit