Linux內核中斷系列之多處理器系統中的中斷處理

處理器間中斷(IPI)
原作者有個Linux中斷專欄系列
多重中斷處理圖示

一、處理器間中斷(核間中斷)

1、在多處理器系統中,操作系統需要在多個處理器間協調操作,通常是通過處理期間中斷(IPI)實現的。
2、IPI是一種特殊的硬件中斷,由處理器發出,被其他處理器接收,以便於處理器間通信或同步。
3、通常並不明確區分IPI和設備中斷,當一個處理器接收到一箇中斷時,如果發現另一個處理器處理該終端更加合理,則可以通過IPI機制將該終端傳遞到其他的處理器,實現處理器的負載平衡。
4、當一個CPU相對另一個CPU發送中斷信號時,就在自己的本地APIC的ICR(中斷命令寄存器)中存放其中斷向量,和目標CPU擁有的本地APIC的標識符,觸發中斷。IPI中斷信號經由APIC總線傳遞到目標APIC,那個收到中斷的APIC就像自己所屬的CPU發送一箇中斷。
5、Linux針對IA32的SMP系統定義了5中IPI,中斷向量號爲251~255:
(1) CALL_FUNCTION_VECTOR:發往除自己以外的所有CPU,強制它們執行指定的函數;
(2) RESCHEDDULE_VECTOR:是終端的CPU重新調度;
(3) INVLIDATE_TLB_VECTOR:使被中斷的CPU廢棄自己的TLB緩存內容;
(4) ERROR_APIC_VECTOR:錯誤的APIC向量,應該從不發生;
(5) SPUROUS_APIC_VECTOR:假的APIC向量,應該從不發生;
另外請參考:http://www.docin.com/p-70820238.html

二、中斷親和力

1、中斷親和力是將一個或多箇中斷服務程序綁定到特定的CPU上運行。
2、中斷親和力通過操作/proc/irq目錄下的文件來控制。對於已註冊的中斷服務程序的硬件設備,在/proc/irq目錄下存在一個該中斷號命名的目錄,該目錄下有一個smp_affinity 文件(SMP體系結構下才有)。它是一個CPU的位掩碼,其中的每一位對應一個CPU,可以用來設置該中斷的親和力,默認爲0xFFFFFFFF,表示把中斷送到所有的CPU上去 處理。如果中斷控制器不支持IRQ affinity,則不能改變此默認值。
注意不能設置爲0x0,即關閉所有CPU對該中斷的處理。
3、利用親和力,可以在多處理系統中均衡各個CPU的負載。

三、中斷負載均衡

是將重負載CPU上的中斷遷移到較空閒的CPU上進行處理;
實現代碼位於arch\i386\kernel\io-apic.c,其中balanced_irq_init函數進行中斷負載均衡模塊兒的初始化,同時創建一個內核線程kirqd用於執行具體的均衡處理。
而kirqd每隔5s調用一次do_irq_balanced函數,進行中斷的遷徙。

static int __init balanced_irq_init(void)
{
	int i;
	struct cpuinfo_x86 *c;
	cpumask_t tmp;
 
 
	cpus_shift_right(tmp, cpu_online_map, 2);
        c = &boot_cpu_data;
	/* When not overwritten by the command line ask subarchitecture. */
	if (irqbalance_disabled == IRQBALANCE_CHECK_ARCH)
		irqbalance_disabled = NO_BALANCE_IRQ;
	if (irqbalance_disabled)
		return 0;
	
	 /* disable irqbalance completely if there is only one processor online */
	if (num_online_cpus() < 2) {
		irqbalance_disabled = 1;
		return 0;
	}
	/*
	 * Enable physical balance only if more than 1 physical processor
	 * is present
	 */
	if (smp_num_siblings > 1 && !cpus_empty(tmp))
		physical_balance = 1;
 
 
	for (i = 0; i < NR_CPUS; i++) {
		if (!cpu_online(i))
			continue;
		irq_cpu_data[i].irq_delta = kmalloc(sizeof(unsigned long) * NR_IRQS, GFP_KERNEL);
		irq_cpu_data[i].last_irq = kmalloc(sizeof(unsigned long) * NR_IRQS, GFP_KERNEL);
		if (irq_cpu_data[i].irq_delta == NULL || irq_cpu_data[i].last_irq == NULL) {
			printk(KERN_ERR "balanced_irq_init: out of memory");
			goto failed;
		}
		memset(irq_cpu_data[i].irq_delta,0,sizeof(unsigned long) * NR_IRQS);
		memset(irq_cpu_data[i].last_irq,0,sizeof(unsigned long) * NR_IRQS);
	}
	
	printk(KERN_INFO "Starting balanced_irq\n");
	if (kernel_thread(balanced_irq, NULL, CLONE_KERNEL) >= 0) 
		return 0;
	else 
		printk(KERN_ERR "balanced_irq_init: failed to spawn balanced_irq");
failed:
	for (i = 0; i < NR_CPUS; i++) {
		if(irq_cpu_data[i].irq_delta)
			kfree(irq_cpu_data[i].irq_delta);
		if(irq_cpu_data[i].last_irq)
			kfree(irq_cpu_data[i].last_irq);
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章