In kernel 2.4, the stack is defined as follows:
Union task_union {
Struct task_struct task;
Unsigned long stack [init_task_size/sizeof (long)];
};
Init_task_size can only be 8 K.
When the kernel assigns a task_struct structure to each process, two consecutive physical pages (8192 bytes) are actually allocated ),. The bottom part is used as the task_struct structure (about 1 kb), and the top part of the structure is used as the kernel stack (about 7 KB ). Access the task_struct structure of the process itself and use a macro to operate current. It is defined in 2.4 as follows:
# Define current get_current ()
Static inline struct task_struct * get_current (void)
{
Struct task_struct * current;
_ ASM _ ("andl % ESP, % 0;": "= r" (current ):""(~ 8191ul ));
Return Current;
}
~ 8191ul indicates that the minimum 13 BITs is 0, and the remaining bits are all 1. % ESP points to the kernel stack. When the minimum value of % ESP is shielded, the beginning of "two consecutive physical pages" is obtained, which is the beginning of task_struct, the pointer to task_struct is obtained.
In kernel 2.6, the stack is defined as follows:
Union thread_union {
Struct thread_info;
Unsigned long stack [thread_size/sizeof (long)];
};
According to the Kernel configuration, thread_size can be 4 K bytes (1 page) or 8 K bytes (2 pages ). Thread_info is 52 bytes long.
Is the kernel stack when it is set to 8 KB: thread_info at the beginning of the memory zone, the kernel stack grows from the end down. The process descriptor is not in this memory zone, and the thread_info and process descriptor are interconnected through the task and thread_info pointers respectively. So the current definition of getting the current process descriptor is as follows:
# Define current get_current ()
Static inline struct task_struct * get_current (void)
{
Return current_thread_info ()-> task;
}
Static inline struct thread_info * current_thread_info (void)
{
Struct thread_info * ti;
_ ASM _ ("andl % ESP, % 0;": "= r" (Ti ):""(~ (Thread_size-1 )));
Return Ti;
}
Based on the size of thread_size, the 12-bit LSB (4 K) or 13-bit LSB (8 K) of the kernel stack is blocked to obtain the starting position of the kernel stack.
Struct thread_info {
Struct task_struct * task;/* Main Task Structure */
Struct exec_domain * exec_domain;/* execution domain */
Unsigned long flags;/* low level flags */
Unsigned long status;/* thread-synchronous flags */
.....
}
The fork system calls dup_task_struct and runs the following command:
1. Execute alloc_task_struct macro to get the process descriptor for the new process and put the descriptor in the local variable Tsk.
2. Execute the alloc_thread_info macro to obtain an idle memory zone and store the thread_info structure and kernel stack of the new process, and place the address of this memory area field in the local variable Ti (8 K or 4 K, configurable ).
3. Copy the content of the current process descriptor to the task_struct structure pointed to by TSK, and set tsk-> thread_info to Ti.
4. Copy the thread_info descriptor of the current process to Ti, and set Ti-> task to Tsk.
5. the descriptor pointer tsk of the new process is returned.
Static struct task_struct * dup_task_struct (struct task_struct * orig)
{
Struct task_struct * tsk;
Struct thread_info * ti;
Prepare_to_copy (orig );
Tsk = alloc_task_struct ();
If (! Tsk)
Return NULL;
Ti = alloc_thread_info (TSK );
If (! Ti ){
Free_task_struct (TSK );
Return NULL;
}
* Tsk = * orig;
Tsk-> thread_info = Ti;
Setup_thread_stack (tsk, orig );
.....
}
# Define alloc_task_struct () kmem_cache_alloc (task_struct_caclap, gfp_kernel)
# Define alloc_thread_info (TSK )/
(Struct thread_info *) _ get_free_pages (gfp_kernel, thread_order ))
# Endif
The kernel stack space is very limited. Therefore, when writing a program in the kernel, do not define large local variables as much as possible, and do not use recursion (resulting in excessive function call stacks leading to stack overflow ), when space is required, use kmalloc to apply in the heap.