- 論壇徽章:
- 0
|
[從"處理器間中斷-發(fā)送"中的描述可知]:
#define IPI_BITMAP_VECTOR 249
#define IPI_PREEMPT 1
1:已經(jīng)給cpu5發(fā)送了一個中斷向量號為IPI_BITMAP_VECTOR的IPI。
2:并且數(shù)組元素cpu_ipi_pending[5]的第IPI_PREEMPT個bit位被設(shè)置為1。
[從"內(nèi)核如何實現(xiàn)IA32中斷處理"中的描述可知]:
中斷向量號為IPI_BITMAP_VECTOR對應(yīng)的中斷處理程序為函數(shù)IDTVEC(ipi_intr_bitmap_handler)。
此時,cpu5接收到了這個IPI,在執(zhí)行中斷處理程序IDTVEC(ipi_intr_bitmap_handler)前,cpu硬件單元要做一些處理,硬件單元所做的處理可以參考
"內(nèi)核如何實現(xiàn)IA32中斷處理"結(jié)尾的描述。
這里做下面的假設(shè):
1:接收到這個IPI時,cpu5運行在用戶態(tài)。
2:接收到這個IPI時,正在cpu5運行的線程對應(yīng)的struct thread對象簡記為cur_thread。
3:cpu硬件單元已經(jīng)完成了在執(zhí)行中斷處理程序之前的處理。
此時cpu5運行在內(nèi)核態(tài),開始執(zhí)行中斷處理程序IDTVEC(ipi_intr_bitmap_handler),線程cur_thread的內(nèi)核棧如下所示:- ******************************* 內(nèi)核棧頂部 高地址方向
- * *
- * struct pcb對象 *
- * *
- * *
- ******************************* <--cur_thread的td_pcb成員指向這里
- * *
- * 16bytes for vm *
- ******************************* <--cur_thread的內(nèi)核棧棧頂
- * SS *
- *******************************
- * ESP *
- *******************************
- * EFLAGS *
- *******************************
- * CS *
- *******************************
- * EIP *
- ******************************* <--執(zhí)行中斷處理程序IDTVEC(ipi_intr_bitmap_handler)時,esp指向這里
- * SS *
- *******************************
- * 0 *
- *******************************
- * 0 *
- *******************************
- * EAX *
- *******************************
- * ECX *
- *******************************
- * EDX *
- *******************************
- * EBX *
- ******************************* 通過struct trapframe類型的數(shù)據(jù)對象來描述
- * ESP *
- *******************************
- * EBP *
- *******************************
- * ESI *
- *******************************
- * EDI *
- *******************************
- * DS *
- *******************************
- * ES *
- *******************************
- * FS *
- ******************************* <--宏P(guān)USH_FRAME和SET_KERNEL_SREGS執(zhí)行完后,esp指向這里
- * addr(jmp doreti) *
- ******************************* <-- 執(zhí)行call ipi_bitmap_handler指令時esp指向這里
- * *
- * *
- * *
- * *
- * *
- * *
- * *
- * *
- * *
- * *
- *******************************------ 內(nèi)核棧底部 低地址方向
復(fù)制代碼 [IDTVEC(ipi_intr_bitmap_handler)]-中斷向量號IPI_BITMAP_VECTOR對應(yīng)的中斷處理程序:- 304 IDTVEC(ipi_intr_bitmap_handler)
- /*******************************************************************************
- * 305,宏P(guān)USH_FRAME,該宏如下所示:
- 將線程cur_thread的用戶態(tài)硬件上下文的一部分壓入內(nèi)核棧中。
- 306,宏SET_KERNEL_SREGS,如下所示:
- 設(shè)置內(nèi)核使用的段寄存器。
- 307:
- 清DF標(biāo)志,string operations increment the index registers (ESI and/or EDI).
- ******************************************************/
- 305 PUSH_FRAME
- 306 SET_KERNEL_SREGS
- 307 cld
- 308
- /*******************************************************************
- * 309-310:
- 通過lapic訪問cpu5的local APIC寄存器組。
- 這里將對local APIC寄存器組中的EOI Register執(zhí)行一個寫操作,這是
- APIC要求的,作為對這個寫操作的響應(yīng),cpu將:
- Upon receiving an EOI, the APIC clears the highest
- priority bit in the ISR and dispatches the next highest
- priority interrupt to the processor
- **********************************************/
- 309 movl lapic, %edx
- 310 movl $0, LA_EOI(%edx) /* End Of Interrupt to APIC */
- 311
- 312 FAKE_MCOUNT(TF_EIP(%esp))
- 313
- /**********************************************************************
- * 314:
- 通過上面內(nèi)核棧的布局,可以明顯的看出,函數(shù)ipi_bitmap_handler
- 的參數(shù)是一個struct trapframe類型的對象,而不是指向這個對象的指針。
- 316:
- doreti函數(shù)完成返回中斷前的處理,這個暫時略過。
- *********************************/
- 314 call ipi_bitmap_handler
- 315 MEXITCOUNT
- 316 jmp doreti
- 317 #endif
復(fù)制代碼 [宏P(guān)USH_FRAME]:- /*****************************************************************************************
- * Macros to create and destroy a trap frame.
- pushal指令:
- Pushes the contents of the general-purpose registers onto the stack. The registers
- are stored on the stack in the following order: EAX, ECX, EDX, EBX, ESP (original
- value), EBP, ESI, and EDI (if the current operand-size attribute is 32)。
- *********************************************/
- 145 #define PUSH_FRAME \
- 146 pushl $0 ; /* dummy error code */ \
- 147 pushl $0 ; /* dummy trap type */ \
- 148 pushal ; /* 8 ints */ \
- 149 pushl %ds ; /* save data and extra segments ... */ \
- 150 pushl %es ; \
- 151 pushl %fs
復(fù)制代碼 [宏SET_KERNEL_SREGS]:- /**********************************************************************************
- * Setup the kernel segment registers.
- 此時cpu5運行在內(nèi)核態(tài),段寄存器也要更改。
-
- 173-175:
- 用內(nèi)核數(shù)據(jù)段的segment selector,即KDSEL加載DS,ES兩個寄存器,訪問內(nèi)核數(shù)據(jù)。
- 176-177:
- 用KPSEL加載FS寄存器,這樣就能訪問數(shù)據(jù)對象__pcpu[5],也是宏P(guān)CPU_*的基礎(chǔ)。
- ******************************************/
- 172 #define SET_KERNEL_SREGS \
- 173 movl $KDSEL, %eax ; /* reload with kernel's data segment */ \
- 174 movl %eax, %ds ; \
- 175 movl %eax, %es ; \
- 176 movl $KPSEL, %eax ; /* reload with per-CPU data segment */ \
- 177 movl %eax, %fs
復(fù)制代碼 [函數(shù)ipi_bitmap_handler]:- /***********************************************************************
- * 參數(shù)描述:
- frame:用來訪問保存在線程cur_thread內(nèi)核棧上用戶態(tài)硬件上下文。
- ****************************/
- 1355 void
- 1356 ipi_bitmap_handler(struct trapframe frame)
- 1357 {
- /***************************************************************************
- * 1360,cpu:PCPU_GET宏獲取當(dāng)前cpu的logical cpu id,這里為5.
- *******************************/
- 1358 struct trapframe *oldframe;
- 1359 struct thread *td;
- 1360 int cpu = PCPU_GET(cpuid);
- 1361 u_int ipi_bitmap;
- /**************************************************************************
- * 1364:td指向當(dāng)前正在運行線程的struct thread對象,這里為&cur_thread。
- 1365:
- 遞增td_intr_nesting_level,即遞增中斷嵌套層數(shù)。
- 1366-1367:
- struct thread對象的td_intr_frame成員,freebsd8.3中沒有該成員,添加的
- 這個成員個人理解為,該成員在中斷處理程序中使用,用來訪問保存在線程
- 內(nèi)核棧上的硬件上下文。
- 1368:
- 函數(shù)atomic_readandclear_int返回數(shù)組元素cpu_ipi_pending[5]的值,然后
- 將其清零。
- *****************************/
- 1363 critical_enter();
- 1364 td = curthread;
- 1365 td->td_intr_nesting_level++;
- 1366 oldframe = td->td_intr_frame;
- 1367 td->td_intr_frame = &frame;
- 1368 ipi_bitmap = atomic_readandclear_int(&cpu_ipi_pending[cpu]);
- /****************************************************************************
- * 三個特殊的IPI如下:
- * #define IPI_AST 0
- #define IPI_PREEMPT 1
- #define IPI_HARDCLOCK 2
- * 1369-1386:
- 依次測試變量的ipi_bitmap的第1,0,2個比特位,檢查發(fā)送
- 的是上面三個特殊IPI的哪一個,并遞增相應(yīng)的計數(shù)器。
- 1369-1374:
- 發(fā)送的是IPI_PREEMPT,此時調(diào)用調(diào)度程序相關(guān)的sched_preempt函數(shù),當(dāng)
- sched_preempt函數(shù)執(zhí)行完后,cpu5上的線程cur_thread被成功搶占。
- 1375-1380:
- 發(fā)送的是IPI_AST,此時不做處理。
- 1381-1386:
- 發(fā)送的是IPI_HARDCLOCK,此時調(diào)用函數(shù)hardclockintr。
- ******************************************************/
- 1369 if (ipi_bitmap & (1 << IPI_PREEMPT)) {
- 1370 #ifdef COUNT_IPIS
- 1371 (*ipi_preempt_counts[cpu])++;
- 1372 #endif
- 1373 sched_preempt(td);
- 1374 }
- 1375 if (ipi_bitmap & (1 << IPI_AST)) {
- 1376 #ifdef COUNT_IPIS
- 1377 (*ipi_ast_counts[cpu])++;
- 1378 #endif
- 1379 /* Nothing to do for AST */
- 1380 }
- 1381 if (ipi_bitmap & (1 << IPI_HARDCLOCK)) {
- 1382 #ifdef COUNT_IPIS
- 1383 (*ipi_hardclock_counts[cpu])++;
- 1384 #endif
- 1385 hardclockintr();
- 1386 }
- /********************************************************
- * 1387:將td_intr_frame成員恢復(fù)到之前的值。
- 1388:遞減td_intr_nesting_level,即中斷嵌套數(shù)減1.
- *******************************/
- 1387 td->td_intr_frame = oldframe;
- 1388 td->td_intr_nesting_level--;
- 1389 critical_exit();
- 1390 }
復(fù)制代碼 [ULE線程調(diào)度-sched_preempt函數(shù)]:- /*******************************************************************
- * 函數(shù)sched_preempt就是調(diào)用mi_switch函數(shù)執(zhí)行一個線程切換,執(zhí)行
- 完后,線程cur_thread被成功搶占。
- 2130:tdq此時為&tdq_cpu[5].
- 2132:將tdq_ipipending設(shè)置為0,表示相應(yīng)的IPI已經(jīng)處理。
- 2133-2143:
- 再次檢查是否需要搶占線程cur_thread,這里簡單的比較兩個優(yōu)先級。
- 如果需要搶占,就設(shè)置合適的標(biāo)志來調(diào)用mi_switch函數(shù)完成線程切換。
- ***********************************/
- 2122 void
- 2123 sched_preempt(struct thread *td)
- 2124 {
- 2125 struct tdq *tdq;
- 2126
- 2127 SDT_PROBE2(sched, , , surrender, td, td->td_proc);
- 2128
- 2129 thread_lock(td);
- 2130 tdq = TDQ_SELF();
- 2131 TDQ_LOCK_ASSERT(tdq, MA_OWNED);
- 2132 tdq->tdq_ipipending = 0;
- 2133 if (td->td_priority > tdq->tdq_lowpri) {
- 2134 int flags;
- 2135
- 2136 flags = SW_INVOL | SW_PREEMPT;
- 2137 if (td->td_critnest > 1)
- 2138 td->td_owepreempt = 1;
- 2139 else if (TD_IS_IDLETHREAD(td))
- 2140 mi_switch(flags | SWT_REMOTEWAKEIDLE, NULL);
- 2141 else
- 2142 mi_switch(flags | SWT_REMOTEPREEMPT, NULL);
- 2143 }
- 2144 thread_unlock(td);
- 2145 }]
復(fù)制代碼 |
|