国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Linux > 正文

內核源碼分析之linux內核棧(基于3.16-rc4)

2024-06-28 13:25:04
字體:
來源:轉載
供稿:網友
內核源碼分析之linux內核棧(基于3.16-rc4)

在3.16-rc4內核源碼中,內核給每個進程分配的內核棧大小為8KB。這個內核棧被稱為異常棧,在進程的內核空間運行時或者執行異常處理程序時,使用的都是異常棧,看下異常棧的代碼(include/linux/sched.h):

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

THREAD_SIZE值為8KB,因此內核為進程的異常棧(內核棧)分配了兩個頁框大小(頁框大小4KB)。另外,進程的thread_info結構體保存在棧頂部。

此外,內核為每個cpu分配一個硬中斷棧和一個軟中斷棧(這兩個棧也是內核棧),用來執行中斷服務例程和下半部(軟中斷),看看代碼(arch/x86/kernel/irq_32.c)。這兩個棧屬于cpu,不屬于進程,這和異常棧是有區別的。

1 DEFINE_PER_CPU(struct irq_stack *, hardirq_stack);2 DEFINE_PER_CPU(struct irq_stack *, softirq_stack);

定義了兩個數組hardirq_stack和softirq_stack,每個數組元素對應一個cpu,指向了該cpu的硬中斷?;蛘哕浿袛鄺?。再來看下struct irq_stack結構體(arch/x86/include/asm/PRocessor.h):

1 struct irq_stack {2     u32                     stack[THREAD_SIZE/sizeof(u32)];3 } __aligned(THREAD_SIZE);

可見,硬中斷棧和軟中斷棧的大小均為8KB。

內核在執行中斷處理程序時,在do_IRQ函數中會調用handle_irq函數,在handle_irq函數中要進行堆棧切換,代碼如下(arch/x86/kernel/irq_32.c):

 1 bool handle_irq(unsigned irq, struct pt_regs *regs) 2 { 3     struct irq_desc *desc; 4     int overflow; 5  6     overflow = check_stack_overflow(); 7  8     desc = irq_to_desc(irq); 9     if (unlikely(!desc))10         return false;11 12     if (user_mode_vm(regs) || !execute_on_irq_stack(overflow, desc, irq)) {13         if (unlikely(overflow))14             print_stack_overflow();15         desc->handle_irq(irq, desc);16     }17 18     return true;19 }

第12行中執行execute_on_irq_stack函數來判斷是否需要堆棧切換,如果不需要,則執行if體的中斷服務例程,即在當前堆棧中執行中斷服務例程,如果需要切換堆棧,則在execute_on_irq_stack函數中切換堆棧并在該函數中(新堆棧中)執行中斷服務例程。下面看下execute_on_irq_stack代碼(arch/x86/kernel/irq_32.c):

 1 static inline int 2 execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq) 3 { 4     struct irq_stack *curstk, *irqstk; 5     u32 *isp, *prev_esp, arg1, arg2; 6  7     curstk = (struct irq_stack *) current_stack(); 8     irqstk = __this_cpu_read(hardirq_stack); 9 10     /*11      * this is where we switch to the IRQ stack. However, if we are12      * already using the IRQ stack (because we interrupted a hardirq13      * handler) we can't do that and just have to keep using the14      * current stack (which is the irq stack already after all)15      */16     if (unlikely(curstk == irqstk))17         return 0;18 19     isp = (u32 *) ((char *)irqstk + sizeof(*irqstk));20 21     /* Save the next esp at the bottom of the stack */22     prev_esp = (u32 *)irqstk;23     *prev_esp = current_stack_pointer;24 25     if (unlikely(overflow))26         call_on_stack(print_stack_overflow, isp);27 28     asm volatile("xchgl    %%ebx,%%esp    /n"29              "call    *%%edi        /n"30              "movl    %%ebx,%%esp    /n"31              : "=a" (arg1), "=d" (arg2), "=b" (isp)32              :  "0" (irq),   "1" (desc),  "2" (isp),33             "D" (desc->handle_irq)34              : "memory", "cc", "ecx");35     return 1;36 }

第7行獲取當前堆棧的指針,第8行獲取本地cpu的硬中斷棧指針,第16行對二者進行比較,如果相等,則不需要切換堆棧(說明當前堆棧就是硬中斷棧,也說明是在中斷處理程序中時又發生了中斷)。如果不相等,就要進行堆棧切換,第22-23行將當前堆棧指針保存在將要切換到的堆棧中(用于返回)。第28行,交換ebx和esp寄存器的值(實現了堆棧切換,將中斷棧指針給了esp),第29行跳轉到相應的中斷服務例程,第30行從中斷服務例程返回后,又將原來的堆棧指針賦給esp,切換到原先堆棧。第33行將中斷服務例程函數名存放在%edi中。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 成安县| 大石桥市| 房山区| 内江市| 汉沽区| 筠连县| 邹平县| 普定县| 永登县| 宝应县| 天全县| 多伦县| 苗栗县| 黄大仙区| 古丈县| 青阳县| 大方县| 大田县| 二连浩特市| 威海市| 枣阳市| 武强县| 南召县| 宁海县| 蓬莱市| 岳普湖县| 南丹县| 定结县| 称多县| 景谷| 昌吉市| 大石桥市| 唐河县| 漳浦县| 高淳县| 大港区| 曲阳县| 肇庆市| 沿河| 扎兰屯市| 五河县|