在內核中,可以通過current宏來獲得當前執行進程的task_struct指針。現在來簡要分析以下:
最原始的定義如下:
#define current get_current()
#define get_current() (current_thread_info()->task) 可以看出,current調用了 current_thread_info函數,此函數的內核路徑為: arch/arm/include/asm/thread_info.h,內核版本為2.6.32.65
static inline struct thread_info *current_thread_info(void)
{
register unsigned long sp asm ("sp");
return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));
}
其中 thread_info結構體如下:
struct thread_info { unsigned long flags; /* low level flags */ int preempt_count; /* 0 => preemptable, <0 => bug */ mm_segment_t addr_limit; /* address limit */ struct task_struct *task; /* main task structure */ struct exec_domain *exec_domain; /* execution domain */ __u32 cpu; /* cpu */ __u32 cpu_domain; /* cpu domain */ struct cpu_context_save cpu_context; /* cpu context */ __u32 syscall; /* syscall number */ __u8 used_cp[16]; /* thread used copro */ unsigned long tp_value; struct crunch_state crunchstate; union fp_state fpstate __attribute__((aligned(8))); union vfp_state vfpstate; #ifdef CONFIG_ARM_THUMBEE unsigned long thumbee_state; /* ThumbEE Handler Base register */ #endif struct restart_block restart_block; };
當內核線程執行到此處時,其SP堆棧指針指向調用進程所對應的內核線程的棧頂。通過 sp & ~(THREAD_SIZE-1)向上對齊,達到棧底部。如下圖所示
將結果強制類型轉換為thread_info類型,此類型中有一個成員為task_struct,它就是 當前正在運行進程的 task_struct指針。
備注:
在內核中,進程的task_struct是由slab分配器來分配的,slab分配器的優點是對象復用和緩存着色。
聯合體:
#define THREAD_SIZE 8192 //內核線程棧 可以通過內核配置成4K 或者 8K ,此處是8K 。在X86體系結構上,32位的內核棧為8K,64位的為16K。
union thread_union {
struct thread_info thread_info; // sizeof(thread_info) =
unsigned long stack[THREAD_SIZE/sizeof(long)]; //stack 大小為 8K,union聯合體的地址是嚴格按照小端排布的,因此,內核棧的低位地址是thread_info結構體。
};
整個8K的空間,頂部供進程堆棧使用,最下部為thread_info。從用戶態切換到內核態時,進程的內核棧還是空的,所以sp寄存器指向棧頂,一旦有數據寫入,sp的值就會遞減,內核棧按需擴展,理論上最大可擴展到 【8192- sizeof(thread_info) 】大小,考慮到函數的現場保護,往往不會有這么大的棧空間。內核在代表進程執行時和所有的中斷服務程序執行時,共享8K的內核棧。