Home  >  Article  >  System Tutorial  >  Understanding the Linux process kernel stack

Understanding the Linux process kernel stack

PHPz
PHPzforward
2024-02-10 18:09:411301browse

When I re-read "LDD3", I found a sentence that I had ignored: "The kernel has a very small stack, it may only be as small as a 4096-byte page." In response to this sentence, I Briefly studied the "kernel stack" of the process.

What is the "kernel stack" of a process? In the life cycle of each process, it will inevitably be trapped in the kernel through system calls. After executing a system call and trapping in the kernel, the stack used by these kernel codes is not the original stack in user space, but a stack in kernel space, which is the "kernel stack" of the process.

For example, a simple character driver implements the open() method. After this driver is mounted, the application calls the Linux open() system call through the glib library. When a system call is executed and trapped in the kernel, the processor will transition to privileged mode (the specific transition mechanism varies depending on the processor architecture. For example, for ARM, the stack pointer (SP) in normal mode and user mode is a different register). At this time, the stack pointer used is the kernel stack pointer, which points to the kernel stack space allocated by the kernel for each process.

The role of the kernel stack My personal understanding is: after falling into the kernel, there are also function calls and automatic variables in system calls, which require stack support. The user space stack is obviously unsafe and therefore requires kernel stack support. In addition, the kernel stack is also used to save some application layer information before system calls (for example, user space stack pointer and system call parameters).

Association between kernel stack and process structure Each process will get a kernel stack space when it is created. The correspondence between the kernel stack and the process is completed through the pointer members in the two structures: (1) struct task_struct A structure that must be learned when learning Linux process management. It represents a process in the kernel and records all status information of the process. This structure is defined in Sched.h (include\linux). There is a member void *stack, which points to the "bottom" of the kernel stack structure below. When the system is running, the macro current obtains the struct task_struct structure of the current process.

(2) Kernel stack structure union thread_union

1. union thread_union {
2.   struct thread_info thread_info;
3.   unsigned long stack[THREAD_SIZE/sizeof(long)];
4. };

The struct thread_info is a structure that records part of the process information, including process context information:

1. /*
2.  \* low level task data that entry.S needs immediate access to.
3.  \* __switch_to() assumes cpu_context follows immediately after cpu_domain.
4.  */
5. struct thread_info {
6.   unsigned long    flags;    /* low level flags */
7.   int      preempt_count;  /* 0 => preemptable,  bug */
8.   mm_segment_t    addr_limit;  /* address limit */
9.   struct task_struct  *task;    /* main task structure */
10.   struct exec_domain  *exec_domain;  /* execution domain */
11.   __u32      cpu;    /* cpu */
12.   __u32      cpu_domain;  /* cpu domain */
13.   struct cpu_context_save  cpu_context;  /* cpu context */
14.   __u32      syscall;  /* syscall number */
15.   __u8      used_cp[16];  /* thread used copro */
16.   unsigned long    tp_value;
17.   struct crunch_state  crunchstate;
18.   union fp_state    fpstate __attribute__((aligned(8)));
19.   union vfp_state    vfpstate;
20. \#ifdef CONFIG_ARM_THUMBEE
21.   unsigned long    thumbee_state;  /* ThumbEE Handler Base register */
22. \#endif
23.   struct restart_block  restart_block;
24. };

The key is the task member, which points to the struct task_struct structure of the created process

The stack member is the kernel stack. It can be seen from here that the kernel stack space and thread_info share a space. If the kernel stack overflows, thread_info will be destroyed and the system will crash~~~

The relationship between kernel stack—struct thread_info—struct task_struct is shown in the figure below:

Understanding the Linux process kernel stack

Generation of kernel stack
When a process is created, the system call of the fork family will allocate space for the kernel stack and struct task_struct respectively. The calling process is:

System calls of the fork family—>do_fork—>copy_process—>dup_task_struct

In the dup_task_struct function:

1. static struct task_struct *dup_task_struct(struct task_struct *orig)
2. {
3.   struct task_struct *tsk;
4.   struct thread_info *ti;
5.   unsigned long *stackend;
6.  
7.   int err;
8.  
9.   prepare_to_copy(orig);
10.  
11.   **tsk = alloc_task_struct();**
12.   if (!tsk)
13. ​    return NULL;
14.  
15.   **ti = alloc_thread_info(tsk);**
16.   if (!ti) {
17. ​    free_task_struct(tsk);
18. ​    return NULL;
19.   }
20.  
21.    err = arch_dup_task_struct(tsk, orig);
22.   if (err)
23. ​    goto out;
24.  
25.   **tsk->stack = ti;**
26.  
27.   err = prop_local_init_single(&tsk->dirties);
28.   if (err)
29. ​    goto out;
30.  
31.   **setup_thread_stack(tsk, orig);**
32. ......

 

alloc_task_struct uses the kernel's slab allocator to allocate the space of struct task_struct for the process to be created
Alloc_thread_info uses the kernel's partner system to allocate kernel stack (union thread_union) space for the process to be created

Note:
The following tsk->stack = ti; statement is related to the struct task_struct and the kernel stack
In setup_thread_stack(tsk, orig);, the kernel stack and struct task_struct are associated:

1. static inline void setup_thread_stack(struct task_struct *p, struct task_struct *org)
2. {
3.   *task_thread_info(p) = *task_thread_info(org);
4.   task_thread_info(p)->task = p;
5. }

Kernel stack size
Since each process is allocated a kernel stack space, it is impossible to allocate a large amount. This size is architecture dependent and is generally measured in pages. In fact, it is the THREAD_SIZE we saw above. This value is generally 4K or 8K. For ARM architecture, this is defined in Thread_info.h (arch\arm\include\asm),

1. \#define THREAD_SIZE_ORDER  1
2. \#define THREAD_SIZE   8192
3. \#define THREAD_START_SP   (THREAD_SIZE - 8)

So ARM’s kernel stack is 8KB

Issues that need to be paid attention to when programming (kernel) drivers:
Due to the limitation of stack space, when writing drivers (especially low-level functions used by system calls), attention should be paid to avoiding codes that consume a large amount of stack space, such as recursive algorithms, the size of local automatic variable definitions, etc.

The above is the detailed content of Understanding the Linux process kernel stack. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:lxlinux.net. If there is any infringement, please contact admin@php.cn delete