Home > Article > System Tutorial > Understanding the Linux process kernel stack
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:
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!