You are on page 1of 18

NGҲT VÀ TRÌNH XӰ LÝ NGҲT

Trách nhiӋm cӕt lõi cӫa hҥt nhân bҩt kǤ hӋ điӅu hành nào đó là qu ҧn lý phҫn cӭng đã kӃt
nӕi tӟi máy tính như: s a cӭng, đĩa blu-ray, bàn phím, chuӝt, vi xӱ lý 3D, đài phát không
dây... ĐӇ đáp ӭng khҧ năng này, hҥt nhân hӋ điӅu hành cҫn phҧi giao tiӃp vӟi các thiӃt bӏ
riêng biӋt cӫa máy tính. ViӋc cho vi xӱ lý có tӕc đӝ xӱ lý lӟn hơn cc phҫn cӭng chúng giao
tiӃp, đó không phҧi là ý tưӣng cӫa nhân hӋ điӅu hành cho vҩn đӅ yêu cҫu và đӧi phҧn ӭng
tӯ các phҫn cӭng chұm hơn mӝt cách đáng kӇ. Thay vào điӅu này, bӣi vì phҫn cӭng tương
ӕi chұm đӇ phҧn ӭng, hҥt nhân cҫn đưӧc giҧi phóng đӇ giҧi quyӃt các công viӋc khác, chӍ
giao tiӃp vӟi phҫn cӭng khi chúng đã hoàn thành công vi Ӌc cӫa mình.

Làm thӃ nào đӇ vi xӱ lý làm viӋc vӟi phҫn cӭng mà không làm ҧnh hưӣng tӟi hiӋu xuҩt tәng
thӇ cӫa máy tính? Mӝt câu trҧ lӣi cho câu hӓi này đó là ³bӓ phiӃu´. Mӝt cách đӏnh kǤ, hҥt
nhân có thӇ kiӇm tra trҥng thái cӫa phҫn cӭng trong hӋ thӕng và phҧn ӭng lҥi mӝt cách phù
hӧp. Bӓ phiӃu phҧi mҩt chi phí, tuy nhiên nó ph ҧi diӉn ra liên tөc bҩt kӇ phҫn cӭng đang
hoҥt đӝng hoһc đã sҹn sàng. Mӝt giҧi pháp tӕt hơn  l cung cҩp mӝt cơ chӃ đӇ báo hiӋu
cho hҥt nhân khi cҫn đưӧc chú ý. Cơ chӃ này đưӧc gӑi là ³Ngҳt´. Trong chương ny, chng
ta Ӆ cұp tӟi các loҥi ngҳt và làm thӃ nào đӇ hҥt nhân phҧn ӭng vӟi chúng, vӟi mӝt hàm
đһc bӋt gӑi là ³Trình xӱ lý ngҳt´.

1.Các loҥi ngҳt

Ngҳt cho phép phҫn cӭng gӱi tín hiӋu tӟi vi xӱ lý. Ví dө: Khi bҥn gõ phím, trình qu ҧn lý bàn
phím có vҩn đӅ vӟi tín hiӋu điӋn tӟi vi xӱ lý đӇ báo cho hӋ điӅu hành phím v ӯa đưӧc ҩn.
Nhӳng tín hiӋu điӋn đó đưӧc gӑi là nhӳng ³Ngҳt´. Vi xӱ lý nhұn nhӳng ngҳt và tín hiӋu cӫa
hӋ điӅu hành đӇ cho phép hӋ điӅu hành phҧn ӭng vӟi dӳ liӋu mӟi. Các thiӃt bӏ phҫn cӭng
tҥo ra các ngҳt không đӗng bӝ vӟi xung nhӏp vi xӱ lý ± nó có thӇ xҧy ra bҩt cӭ lúc nào. Do
đó hҥt nhân có thӇ bӏ gián đoҥn bҩt cӭ lúc nào đӇ xӱ lý ngҳt.

Ngҳt đưӧc tҥo ra tӯ tín hiӋu điӋn có nguӗn gӕc tӯ các thiӃt bӏ phҫn cӭng và hưӟng vào các
chân đҫu vào cӫa bӝ điӅu khiӇn ngҳt, mӝt chip đơn giҧn có nhiӅu luӗng nhiӅu yêu cҫu ngҳt
đưa vo mӝt dòng đơn tӟi vi xӱ lý. Khi nhұn đưӧc mӝt ngҳt, trình quҧn lý ngҳt gӱi tín hiӋu
tӟi vi xӱ lý. Vi xӱ lý nhұn dҥng tín hiӋu này và ngҳt các thi hành hi Ӌn tҥi đӇ xӱ lý ngҳt. Vi xӱ
lý có thӇ báo cho hӋ điӅu hành có mӝt ngҳt đã xҧy ra, và hӋ điӅu hành có thӇ xӱ lý ngҳt mӝt
cách thích hӧp.

Nhӳng thӃt bӏ khác nhau có thӇ đưӧc ghép vӟi các loҥi ngҳt khác bӣi mӝt giá trӏ duy
nhҩt đưӧc kӃt hӧp vӟi mӛi loҥi ngҳt. Bҵng cách này, ngҳt tӯ bàn phím là khác bi Ӌt vӟi ngҳt
tӯә đĩa cӭng. ĐiӅu này cho phép h Ӌ điӅu hành có thӇ phân biӋt giӳa các loҥi ngҳt và biӃt
thiӃt bӏ phҫn cӭng nào gây ra ng ҳt. Trong trưӡng hӧp này, hӋ điӅu hành có thӇ phөc vө mӛi
ngҳt vӟi bӝ xӱ lý tương ӭng cӫa nó.

Nhӳng giá trӏ cӫa ngҳt thưӡng đưӧc gӑi là nhӳng dòng Interrupt Request (IRQ). M ӛi
mӝt dòng IRQ đưӧc gán mӝt giá trӏ bҵng sӕ. Ví dө: Trong classic PC, IRQ 0 là b ӝ đӃm ngҳt,
IRQ 1 là ngҳt bàn phím. Không ph ҧi tҩt đӅu là sӕ, đó là mӝt đӏnh nghĩa cӭng nhҳc, ví dө:
các ngҳt đưӧc gҳn vӟi các PCI bus đưӧc gán mӝt cách tӵ đӝng. Trên mӝt sӕ kiӃn trúc
không phҧi PC cũng có cách gán đӝng giá trӏ cho các ngҳt. ĐiӅu quan trӑng cҫn chú ý đó là
³mӝt ngҳt cө thӇ đưӧc gҳn vӟi mӝt thiӃt bӏ cө thӇ, và hҥt nhân biӃt điӅu này´. Phҫn cӭng
đưa cc ngҳt đӇ báo cho hҥt nhân: ³Này, tôi có mӝt phím mӟi bҩm và đang chӡ đây, đӑc và
xӱ lý đi cұu bé Ö´.

2.Ngoҥi lӋ:

Trong nhӳng văn bҧn hӋ điӅu hành, nhӳng ngoҥi lӋ thưӡng đưӧc đӅ cұp song hành v ӟi
ngҳt. Không giӕng như ngҳt, ngoҥi lӋ xҧy ra khi đӗng bӝ vӟi xung nhӏp cӫa vi xӱ lý. Thӵc
vұy, chúng thưӡng đưӧc gӑi là đӗng bӝ ngҳt (synchronous interrupts). Ngo ҥi lӋ đưӧc đưa ra
bӣi vi xӱ lý trong khi đang thi hành nh ӳng chӍ thӏ hoһc đӇ phҧn ӭng vӟi lӛi lұp trình (ví dө
như lӛi chia cho sӕ 0). Bӣi vì kiӃn trúc vi xӱ lý xӱ lý ngoҥi lӋ giӕng vӟi ngҳt, cơ sӣ hҥ tҫng
cӫa hҥt nhân cũng xӱ lý giӕng vұy. Đã có nhiӅu đӅ cұp vӅ ngҳt trong chương ny (Ngҳt
không đӗng bӝ đưӧc tҥo ra bӣi phҫn cӭng), cũng gҳn liӅn vӟi ngoҥi lӋ (ngҳt đӗng bӝ đưӧc
tҥo ra bӣi vi xӱ lý).

Trình xӱ lý ngҳt

Chӭc năng cӫa hҥt nhân là chҥy đӇ phҧn ӭng vӟi các loҥi ngҳt đưӧc gӑi là ³interrupt
handler´ (xӱ lý ngҳt) hoһc ISR (interrupt service routine). M ӛi loҥi thiӃt bӏ tҥo nhӳng lҥi ngҳt
có mӝt liên kӃt tӟi Interrupt handler. Ví d ө mӝt hàm quҧn lý ngҳt tӯ hӋ thӕng timer, trong khi
mӝt hàm quҧn lý ngҳt khác đưӧc tҥo ra bӣi bàn phím. Quҧn lý ngҳt cho thiӃt bӏ là mӝt phҫn
cӫa driver thiӃt bӏ - nhân quҧn lý thiӃt bӏ.

Trong Linux, qu ҧn lý ngҳt là nhӳng hàm C thông th ưӡng. Chúng có mӝt nguyên
mүu cө thӇ, cho phép hҥt nhân xӱ lý thông tin trong mӝt chuҭn, nhưng n cng l nhưng
hm thng thưӡng. Có nhӳng điӇm gì khác giӳa Interrupt handlers và nh ӳng hàm khác cӫa
hҥt nhân? Đó là h ҥt nhân gӑi chúng đӇ phҧn ӭng lҥi các ngҳt và chúng đưӧc chҥy trong mӝt
ngӳ cҧnh đһc biӋt đưӧc gӑi là interrupt context (ng ӳ cҧnh ngҳt). Ngӳ cҧnh đһc biӋt này là
ngүu nhiên, đưӧc gӑi là atomic context b ӣi vì, như chng ta  thҩy, đoҥn mã đang đưӧc
thi hành trong ng ӳ cҧnh này không thӇ bӏ block.

Bӣ bì mӝt ngҳt có thӇ xҧy ra bҩt cӭ lúc nào, mӝt xӱ lý ngҳt có thӇ lҫn lưӧt đưӧc
thӵc thi. ĐiӅu bҳt buӝc là quá trình x ӱ lý phҧi thұt nhanh, đӇ quay trӣ lҥi thi hành nhanh nh ҩt
có thӇ nhӳng đoҥn mã đã bӏ gián đoҥn. Vì vұy điӅu quan trӑng là phҫn cӭng phҧi làm cho
hӋ điӅu hành phөc vө ngҳt không chұm trӉ. ĐiӅu quan trӑng nӳa đó là hӋ điӅu hành cҫn xӱ
lý ngҳt mӝt cách ngҳn nhҩt có thӇ.

Ít nhҩt, mӝt công viӋc xӱ lý ngҳt là đӇ xác nhұn ngҳt tӟi phҫn cӭng: ³Này, phҫn
cӭng, tôi đã nghe b ҥn nói, hãy quay l ҥi làm viӋc đi´. Thông thưӡng, mà đôi khi xӱ lý ngҳt có
khӕi lưӧng lӟn công viӋc đӇ xӱ lý.

Top Halves so v ӟi Bottom Halves

Có 2 mөc tiêu: Mӝt là xӱ lý ngҳt thӵc thi nhanh và x ӱ lý khӕi lưӧng lӟn công viӋc. Hai là
giҧi quyӃt rõ ràng các xung đ ӝt vӟi nhau. Bӣi vì đӇ hoàn thành nh ӳng mөc tiêu này, quá
trình xӱ lý cӫa các ngҳt đưӧc chia làm 2 phҫn, hoһc 2 nӱa. Xӱ lý ngҳt đưӧc gӑi là top half
(nӱa trên). Nӱa trên đưӧc chҥy ngay lұp tӭc khi có xác nhұn cӫa ngҳt và chӍ xӱ lý khi nó là
quan trӑng. Chҷng hҥn như viӋc xác nhұn cӫa ngҳt hoһc quay trӣ lҥi phҫn cӭng. Công viӋc
có thӇ đưӧc xӱ lý sau đó, hoãn l ҥi cho tӟi phҫn dưӟi (bottom half). Ph ҫn dưӟi chҥy sau, tҥi
mӝt thӡi gian thuұn tiӋn hơn, vӟi tҩt cҧ các ngҳt. Linux cung cҩp rҩt nhiӅu cơ chӃ thӵc hiӋn
bottom halves (ph ҫn sau).(Nó sӁ đưӧc đӅ cұp trong chương 8 cӫa tài liӋu này).

Nào bây giӡ chúng ta cùng xem mӝt ví dө vӅ sӵ phân đôi top -half/bottom-half, Khi
card mҥng nhұn nhӳng gói tin tӯ mҥng, chúng cҫn thông báo cho h ҥt nhân cӫa chúng vӅ
khҧ năng cӫa chúng. Card mҥng cҫn làm viӋc này ngay lұp tӭc, đӇ tӕi ưu thng lưӧng, đӝ
trӉ và tránh timeout. Ngay l ұp tӭc có mӝt vҩn đӅ ngҳt: ³Này, hҥt nhân, tôi có mӝt sӕ gói tin
mӟi!´. Hҥt nhân phҧn ӭng lҥi bҵng cách thi hành đăng ký ng ҳt cӫa card mҥng. Ngҳt đưӧc
chҥy, xác nhұn phҫn cӭng, sao chép gói tin m ӟi vào bӝ nhӟ chính, và card mҥng sҹn sàng
cho nhӳng gói tin mӟi. Nhưng cng viӋc này là quan tr ӑng, thӡi gian quan tr ӑng, và là
công viӋc riêng cӫa phҫn cӭng. Hҥt nhân cҫn sao chép nhanh nh ӳng gói tin mҥng vào trong
bӝ nhӟ chính bӣi vì bӝ đӋm dӳ liӋu mҥng trong card mҥng là giӟi hҥn và có kích thưӟc nhӓ,
đһc biӋt là so sánh vӟi bӝ nhӟ chính. Thӡi gian trӉ trong quá trình copy gói tin có th Ӈ dүn tӟi
kӃt quҧ là bӝ đӋm bӏ tràn. Các gói tin đ Ӄn bӏ chôn vùi trong mҥng và bӏ mҩt. Sau khi dӳ liӋu
mҥng đã ӣ an toàn trong b ӝ nhӟ chính, công viӋc ngҳt hoàn thành, và nó có th Ӈ quay trӣ vӅ
điӅu khiӇn hӋ thӕng thi hành ti Ӄp các đoҥn mã đã bӏ gián đoҥn trưӟc đó. Phҫn còn lҥi cӫa
quá trình xӱ lý gói tin đưӧc xҧy ra sau này, trong phҫn dưӟi (bottom half). Trong ph ҫn này
chúng ta chӍ xem vӅ phҫn trên (top half).

Đăng ký mӝt trình xӱ lý ngҳt.

Nhӳng trình xӱ lý ngҳt có trách nhiӋm trong viӋc điӅu khiӇn quҧn lý thiӃt bӏ. Mӛi loҥi thiӃt bӏ
đưӧc ghép vӟi mӝt trình điӅu khiӇn, và nӃu thiӃt bӏ đó sӱ dөng ngҳt, sau đó trình đi Ӆu khiӇn
cҫn đăng ký mӝt trình xӱ lý ngҳt.

Trình điӅu khiӇn có thӇ đăng ký mӝt trình xӱ lý ngҳt và cho mӝt yêu cҫu ngҳt đӇ xӱ
lý vӟi hàm request_irq(), đã đ ưӧc khai báo trong <linux/interrupt.h>:

/* request_irq: allocate a given interrupt line */

int request_irq(unsigned int irq,

irq_handler_t handler,

unsigned long flags,

const char *name,

void *dev)

Tham sӕ đҫu tiên irq đӇ chӍ sӕ cӫa ngҳt đưӧc cҩp phát. Mӝt vài thiӃt bӏ ví dө như system
timer hoһc bàn phím, nhӳng giá trӏ này thưӡng đưӧc có đӏnh. Nhӳng thiӃt bӏ khác đưӧc lұp
trình hoàn toàn t ӵ đӝng.

Tham sӕ thӭ hai, handler là đ Ӈ chӍ con trӓ hàm tӟi trình xӱ lý ngҳt hiӋn thӡi đang
phөc vө cho quá trình ng ҳt này. Hàm này đưӧc gӑi ra bҩt kǤ khi hӋ điӅu hành nhұn đưӧc
ngҳt.
typedef irqreturn_t (*irq_handler_t)(int, void *);

Chú ý khai báo nguyên mâu hàm x ӱ lý: Nó có 2 tham sӕ và có giá trӏ trҧ vӅ cӫa irqreturn_t.
Hàm này sӁ đӅ cұp ӣ chương sau.

Interrupt handler flags

Tham sӕ thӭ ba, flags, có thӇ là 0 hoһc mӝt hһc mӝt vài cӡ khác đưӧc đӏnh nghĩa trong
<linux/interrupt.h>. Gi ӳa các flag này, đi Ӆu quan trӑng nhҩt đó là:

IRQF_DISABLED: Khi đưӧc thiӃt lұp, flag này chӍ cho hҥt nhân phҧi vô hiӋu hóa tҩt cҧ các
ngҳt khi thi hành trình x ӱ lý ngҳt nà. Khi không đ ưӧc thiӃt lұp, trình xӱ lý ngҳt chҥy vӟi tҩt
cҧ các ngҳt trӯ bҧn thân nó tӵ kích hoҥt. Hҫu hӃt các trình xӱ lý ngҳt không thiӃt lұp giá trӏ
cho flag này, vô hi Ӌu hóa tҩt cҧ các ngҳt là hình thӭc xҩu. Nó đưӧc sӱ dөng đӇ dành riêng
cho xӱ lý ngҳt đưӧc thi hành nhanh. Flag này là m ӝt biӇu hiӋn cӫa SA_INTERRUPT flag,
cái mà khi trưӟc dùng đӇ đánh dҩu giӳu nhӳng ngҳt nhanh và chұm.

IRQF_SAMPLE_RAMDOM: Flag này ch Ӎ rõ nhӳng ngҳt đưӧc tҥo ra bӣi thiӃt bӏ góp phҫn
tăng khҧ năng ngүu nhiên bҫu chӑn cӫa hҥt nhân. Khҧ năng ngүu nhiӉn bҫu chӑn ngүu
nhiên cӫa hҥt nhân cung cҩp nhӳng con sӕ thӵc sӵ ngүu nhiên xuҩt phát tӯ rҩt nhiӅu sӵ
kiӋn ngүu nhiên. NӃu flag này đưӧc mô tҧ, thì thӡi gian cӫa các ngҳt tӯ thiӃt bӏ là nguӗn đӇ
tҥo ra sӵ bҫu chӑn giӕng như entropy. Khng thiӃt lұp giá trӏ cho nó nӃu thiӃt bӏ cӫa bҥn có
vҩn đӅ vӟi ngҳt tҥi mӝt tӍ lӋ dӵ đoán. Ӣ phía khác, hҫu hӃt các phҫn cӭng tҥo ngҳt tҥi mӝt
thӡi điӇm không xác đinh vì thӃ nó là mӝt nguӗn tài nguyên t ӕt cho entropy.

IRQF_TIMER: Flag này chӍ ra trình xӱ lý ngҳt xӱ lý cho hӋ thӕng timer

IRQF_SHARED: Flag này chӍ ra yêu cҫu ngҳt có thӇ đưӧc chia sҿ giӳa các đa trình xӱ lý
ngҳt. Mӛi trình xӱ lý đưӧc đăng ký trên mӝt dòng cӫa flag này, nói m ӝt cách khác là chӍ có
mӝt trình xӱ lý tӗn tҥi trên mӛi dòng.

Mӝt ví dө vӅ ngҳt:

Trong trình đi Ӆu khiӇn, yêu cҫu mӝt yêu cҫu ngҳt và cài đһt trình xӱ lý đưӧc hoàn thành
thông qua:

if (request_irq(irqn, my_interrupt, IRQF_SHARED, "my_device", my_dev)) {

printk(KERN_ERR "my_device: cannot register IRQ %d \n", irqn);

return -EIO;

Trong ví dө này, irqn là mӝt dòng yêu cҫu đưӧc ngҳt; my_interrupt là trình x ӱ lý; chúng ta đã
chӍ ra thông qua flag r ҵng dòng này có th Ӈ đưӧc chia sҿ; thiӃt bӏ có tên là my_device; và
chúng ta đã h ӧp thӭc hóa my_dev cho dev. Trong tr ưӡng hӧp không thӵc hiӋn đưӧc, đoҥn
code in ra l ӛi và trҧ vӅ giá trӏ. NӃu lӡi gӑi trҧ vӅ 0, trình quҧn xӱ lý đã đưӧc cài đһt thành
công. Tӯ thӡi điӇm này vӅ sau, trình xӱ lý đưӧc gӑi trong viӋc phҧn ӭng vӟi các ngҳt. Nó rҩt
quan trӑng trong vi Ӌc khӣi tҥo và đăng ký trình xӱ lý ngҳt phҫn cӭng theo thӭ tӵ thích hӧp
đӇ ngăn chһn trình xӱ lý ngҳt chҥy trưӟc khi phҫn cӭng đưӧc khӣi tҥo.

Giҧi phóng mӝt trình xӱ lý ngҳt

Khi thiӃt bӏ cӫa bҥn đưӧc giҧi phóng, bҥn cҫn hӫy nhӳng trình xӱ lý ngҳt và phҧi vô hiӋu
nhӳng yêu cҫu ngҳt. ĐӇ làm đưӧc viӋc này, gӑi hàm

void free_irq(unsigned int irq, void *dev)

NӃu nhưyêu cҫu ngҳt đưӧc chӍ ra không đưӧc chia sҿ, hàm trên sӁ loҥi bӓ trình xӱ lý và vô
hiӋu nhӳng dòng này. NӃu nhӳng yêu cҫu ngҳt đưӧc chia sҿ, trình xӱ lý đưӧc nhұn diӋn
thong qua thi Ӄt bӏ nào đã bӏ loҥi bӓ, nhưng nhӳng yêu cҫu ngҳt chӍ đưӧc vô hiӋu khi mà
trình xӱ lý cuӕi cùng đưӧc gӥ bӓ. Bây giӡ bҥn có thӇ thҩy tҥi sao mӝt unique dev là r ҩt quan
trӑng. Vӟi nhӳng yêu cҫu ngҳt đưӧc chia sҿ, mӝt unique cookie ph ҧi đưӧc yêu cҫu đӇ phân
biӋt giӳa nhӳng đa xӱ lý có thӇ tӗn tҥi trong mӝt dòng và cho phép free_irq() ch Ӎ loҥi bӓ
đúng nhӳng trình xӱ lý. Trong trưӡng hӧp khác, (có thӇ đưӧc chia sҿ, hoһc không đưӧc
chia sҿ), nӃu dev không phҧi là Null, nó c ҫn phҧi phù hӧp vӟi trình xӱ lý muӕn có. Mӝt lӡi
gӑi tӟi free_irq() c ҫn phҧi đưӧc tҥo ra tӯ ngӳ cҧnh xӱ lý.

ViӃt mӝt trình xӱ lý ngҳt

Đoҥn mã sau đây khai báo m ӝt trình xӱ lý ngҳt

static irqreturn_t intr_handler(int irq, void *dev)

Chú ý rҵng trong khai báo này ph ҧi giӕng vӟi nguyên mүu cӫa các tham sӕ truyӅn vào cho
trình xӱ lý ӣ request_irq(). Tham s ӕ đҫu tiên irq, nó là giá tr ӏ bҵng sӕ cӫa yêu cҫu ngҳt mà
trình xӱ lý đang phөc vө. Giá trӏ đưӧc chuyӇn vào cho trình xӱ lý, nhưng khng dưӧc sӱ
dөng thưӡng xuyên, trӯ khi in log. Trưӟc phiên bҧn 2.0 cӫa hҥt nhân Linux, không có tham
sӕ dev và chӍ có irq đưӧc sӱ dөng đӇ phân biӋt giӳa nhiӅu thiӃt bӏ sӱ dөng cùng mӝt trình
điӅu khiӇn. Chính vì thӃ nên có cùng mӝt trình xӱ lý ngҳt. Mӝt ví dө cho điӅu này đó là vi Ӌc
máy tính sӱ dөng nhiӅu ӣ đĩa cӭng vӟi cùng mӝt trình điӅu khiӇn.

Tham sӕ thӭ 2, dev, là mӝt con trӓ đӇ trӓ tӟi cùng dev đưӧc đưa cho request_irq() khi mà
trình xӱ lý ngҳt đưӧc đăng ký. NӃu giá trӏ này là duy nhҩt( cái mà đưӧc yêu cҫu hӛ trӧ chia
sҿ), nó có thӇ thӵc thi giӕng mӝt cookie đӇ phân biӋt giӳa nhiӅu thiӃt bӏ sӱ dөng chung mӝt
trình xӱ lý ngҳt. dev cugnx có thӇ trӓ tӟi mӝt cҩu trúc đưcӑ sӱ dөng cho trình xӱ lý ngҳt. Bӣi
vì cҩu trúc thiӃt bӏ cũng là duy nhҩt cho mӛi thiӃt bӏ và nó hӳu ích cho trình xӱ lý, thưӡng
đưӧc truyӅn vào cho dev.

Giá trӏ trҧ vӅ cӫa mӝt trình xӱ lý ngҳt đưӧc chӍ ra là irqreturn_t. M ӝt trình xӱ lý ngҳt có thӇ
trҧ vӅ 2 giá trӏ, IRQ_NONE hoһc IRQ_HANDLED. Giá trӏ thӭ nhҩt đưӧc trҧ vӅ khi trình xӱ lý
ngҳt phát hiӋn mӝt ngҳt cho thiӃt bӏ mà không phҧi do nó khӣi tҥo. Giá trӏ thӭ 2 đưӧc trҧ vӅ
nӃu trình xӱ lý ngҳt đưӧc gӑi mӝt cách chính xác. Ngoài ra, IRQ_RETVAL(val) có th Ӈ đưӧc
sӱ dөng. NӃu val không phҧi là 0, hàm này tr ҧ vӅ IRQ_HANDLED, ngưӧc lҥi trҧ vӅ
IRQ_NONE. Nhӳng giá trӏ đưӧc nêu ra ӣ đây đưӧc sӱ dөng đӇ báo cho hҥt nhân biӃt thiӃt
bӏ nào đưӧc ngҳt giҧ. NӃu tҩt cҧ trình xӱ lý ngҳt đӅu trҧ vӅ IRQ_NONE, sau đó hҥt nhân sӁ
phát hiӋn lӛi. Bҥn có thӇ tò mò vӅ kiӇu trҧ vӅ irqreturn_t, nó r ҩt đơn giҧn là mӝt kiӇu nguyên.
Giá trӏ này đưӧc cung cҩp tương th ch ngưӧc vӟi các hҥt nhân cũ. Trưӟc phiên bҧn 2.6.
trình xӱ lý ngҳt trҧ vӅ giá trӏ void. Trình điӅu khiӇn có thӅ dӉ dàng đӏnh nghĩa irqreturn_t
thành void đӇ làm viӋc vӟi phiên bҧn 2.4 mà không c ҫn phҧi có sӵ chӍnh sӱa nào. Trình x ӱ
lý ngҳt thưӡng đưӧc đánh dҩu là static bӣi vì nó không bao giӡ đưӧc gӑi trӵc tiӃp tӯ file
khác.

Vai trò cӫa trình xӱ lý ngát phө thuӝc hoàn toàn vào thi Ӄt bӏ và đó là lý do cho v Ӌc cҩp phát
ngҳt. Mӝt thӡi gian ngҳn, hҫu hӃt tҩt cҧ các trình xӱ lý ngҳt cҫn phҧi cho biӃt thiӃt bӏ nào
đưӧc nhұn ngҳt này. Nhӳng thiӃt bӏ rҩt phӭc tҥp, cҫn phҧi bә xung them viӋc gӱi và nhұn
dӳ liӋu đӇ làm viӋc vӟi các trình xӱ lý ngҳt.

Trình xӱ lý chia sҿ.

Mӝt trình xӱ lý chia sҿ đưӧc đăng ký và đưӧc thi hành gi ӕng như mӝt trình xӱ lý không chia
sҿ. Nhưng c 3 iӇm khác

Cӡ IRQF_SHARED cҫn đưӧc thiӃt lұp trong tham sӕ flags tӟi hàm request_irq()

Tham sӕ dev phҧi là duy nhҩt cho mӛi trình xӱ lý đưӧc đăng ký. Mӝt con trӓ bҩt kǤ cho mӛi
thiӃt bӏ là mӝt cҩu trúc đáp ӭng đưӧc. Mӝt sӵ lӵa chӑn chung là cҩu trúc thiӃt bӏ cũng duy
nhҩt. Bҥn không thӇ nào truyӅn NULL vào cho trình x ӱ lý chia sҿ.

Mӝt trình xӱ lý ngҳt cҫn có khҧ năng phân bi Ӌt bҩt kӇ khi thiӃt bӏ nó quҧn lý tҥo ra mӝt ngҳt.
ĐiӅu này yêu cҫu cҧ phҫn cӭng hӛ trӧ và kӃt hӧp logic vӟi trình xӱ lý ngҳt. NӃu phҫn cӭng
không đáp ӭng khҧ năng này, thì không còn cách nào đ Ӈ trình xӱ lý ngҳt biӃt đưӧc thiӃt bӏ
chia sҿ nào là nguyên nhân sinh ra ng ҳt.

Tҩ cҧ thiӃt bӏ chia sҿyêu cҫu ngҳt cҫn phҧi đáp ӭng các yêu cҫu trên. NӃu mӝt thiӃu bӏ
không chia sҿ công bҵng thì không thӇ có dòng chia sҿ. Khi hàm request_irq() đưӧc gӑi vói
IRQF_SHARED đưӧc mô tҧ, lӡi gӑi này chӍ thành công khi yêu cҫu ngҳt chưa ưӧc đăng
ký, hoһc tҩt cҧ các trình xӱ lý đưӧc đăng ký trên yêu cҫu ngҳt đó cũng đưӧc mô tҧ
IRQF_SHARED. Mӝt trình xӱ lý chia sҿ, thӍnh thoҧng có thӇ kӃt hӧp vӟi IRQF_DISABLED.

Khi hҥt nhân nhұn đưӧc mӝt ngҳt, nó gӑi ra tuҫn tӵ các trình xӱ lý đã đưӧc đăng ký trên
dòng đó. Trình x ӱ lý cҫn phҧi nhanh chóng thoát n Ӄu nó không đưӧc liên kӃt vӟi thiӃt bӏ tҥo
ra ngҳt. ĐiӅu này hiêu cҫu phҫn cӭng phҧi có trҥng thái đăng ký, và trình x ӱ lý có thӇ kiӇm
tra. Hҫu hӃt các phҫn cӭng đӅu có khҧ năng này.

Thӵc tӃ vӅ mӝt trình xӱ lý ngҳt

Nào chúng ta hãy cùng xem m ӝt trình xӱ lý ngҳt tӯ bӝ phұn điӅu khiӇn thӡi gian thӵc(RTC),
đưӧc tìm thҩy trong drivers/char/rtc.c. RTC đ ưӧc tìm thҩy trong rҩt nhiӅu máy, có cҧ PC. Nó
là mӝt thiӃt bӏ đưӧc tách ra tӯ hӋ thӕng timer, cái mà thi Ӄt lұp giӡ hӋ thӕng, cung cҩp mӝt
cҧnh báo, hoһc hӛ trӧ bӝ đӃm đӏnh kǤ. Trên hҫu hӃt các kiӃn trúc, hӋ thӕng thӡi gian đưӧc
thiӃt lұp bҵng cách viӃt mӝt yêu cҫu thӡi gian vào mӝt thanh ghi c ө thӇ hoһc mӝt vùng I/O.
Bҩt kǤ cҧnh báo hoһc bӝ đӃm đӏnh kǤ, chӭc năng thưӡng đưӧc cài đһt thong qua ngҳt. Ngҳt
tương ương vӟi mӝt đӗng hӗ báo thӭc thӡi gian thӵc.

Khi trình đi Ӆu khiӇn RTC đưӧc nҥp, hàm rtc_init() đ ưӧc gӑi đӇ khӣi tҥo trình điӅu khiӇn. Mӝt
trong nhӳng nhiӋm vө cӫa nó là đӇ đăng ký xӱ lý ngҳt.
/* register rtc_interrupt on rtc_irq */

if (request_irq(rtc_irq, rtc_interrupt, IRQF_SHARED, "rtc", (void *)&rtc_port)) {

printk(KERN_ERR "rtc: cannot regist er IRQ %d\n", rtc_irq);

return -EIO;

Trong ví dө này yêu cҫu ngҳt đưӧc chӭa trong rtc_irq. Bi Ӄn này đưӧc thiӃt lұp cho ngҳt
RTC cho cҩu trúc đưӧc đưa ra. Trîn PC, RTC ưӧc đӏnh vӏӣ IRQ 8. Tham sӕ thӭ 2 là trình
xӱ lý, rtc_interrupt, sҹn sang chia sҿyêu cҫu ngҳt vӟi trình xӱ lý khác, thong qua c ӡ
IRQ_SHARED. Thӯ tham sӕ thӭ 4 bҥn có thӇ thҩy tên thiӃt bӏ là rtc.

Và đây là đoҥn mã cӫa trình xӱ lý ngҳt rtc:

static irqreturn_t rtc_interrupt(int irq, void *dev)

/*

* Can be an alarm interrupt, update compl ete interrupt,

* or a periodic interrupt. We store the status in the

* low byte and the number of interrupts received since

* the last read in the remainder of rtc_irq_data.

*/

spin_lock(&rtc_lock);

rtc_irq_data += 0x100;

rtc_irq_data &= ~0xff;

rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);

if (rtc_status & RTC_TIMER_ON)

mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);

spin_unlock(&rtc_lock);

/*

* Now do the rest of the actions

*/

spin_lock(&rtc_task_lock);

if (rtc_callback)
rtc_callback->func(rtc_callback->private_data);

spin_unlock(&rtc_task_lock);

wake_up_interruptible(&rtc_wait);

kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);

return IRQ_HANDLED;

Hàm này đưӧc gӑi bҩt kӇ khi nào máy nhұn đưӧc ngҳt RTC. Nhưng thӭ nhҩt phҧi chú ý
rtc_irq_data không đ ưӧc truy cұp đӗng thӡi bӣi vi xӱ lý khác trên mӝt hӋ thӕng SMP, và thӭ
hai là thiӃt lұp bҧo bӋ rtc_callback.

rtc_irq_data là bi Ӄn unsigned long dùng đ Ӈ lưu trӳ thông tin v Ӆ RTC và đưӧc cұp nhұt mӛi
khi ngҳt phҧn ánh vӅ trҥng thái cӫa ngҳt đó.

TiӃp theo nӃu như RTC preodic timer ưӧc thiӃt lұp, nó đưӧc cұp nhұt thông qua hàm
mod_timer().

Đoҥn cuӕi cӫa đoҥn code, dưӟi dòng comment là đ Ӈ gӑi lҥi mӝt hàm có sҹn. Trình điӅu
khiӇn RTC cho phép hàm g ӑi lҥi có thӇ đưӧc đăng ký và thi hành trên mӛi ngҳt cӫa RTC.

Cuӕi cùng hàm trҧ vӅ IRQ_HANDLED báo hiӋu là đã xӱ lý thiӃt bӏ này.

Ngӳ cҧnh ngҳt

Khi thӵc hiӋn mӝt bӝ xӱ lý ngҳt, hҥt nhân đang ӣ tai ngӳ cҧnh ngҳt. Nhӟ lҥi quá trình ngӳ
cҧnh đang chӃ đӝ hoҥt đӝng hҥt nhân trong khi đang th ӵc hiӋn thay cho mӝt cuӝc gӑi mӝt
quá trình ví dө, thӵc hiӋn hӋ thӕng hoһc chҥy mӝt chӫ đӅ hҥt nhân. Trong quá trình ng ӳ
cҧnh, các vĩ mô hiӋn tҥi chӍ đӃn nhiӋm vө liên quan. H ơn nӳa, vì mӝt quá trình cùng v ӟi các
hҥt nhân ӣ tҥi quá trình ngӳ cҧnh, quá trình ngӳ cҧnh có thӇ ngӫ hoһc nӃu không, gӑi các
lӏch trình.

ngӳ cҧnh ngҳt, mһt khác, không liên k Ӄt vӟi mӝt quá trình. Các vĩ mô hi Ӌn nay đang không
có liên quan (m һc dù nó chӍ đӃn quá trình ngҳt). NӃu không có mӝt quá trình sao l ưu, ngӳ
cҧnh ngҳt không thӇ ngӫ, làm thӃ nào mà nó bao gi ӡ sҳp xӃp lҥi? Do đó, bҥn không thӇ gӑi
chӭc năng nhҩt đӏnh tӯ ngӳ cҧnh ngҳt. NӃu chӭc năng ngӫ, bҥn không thӇ sӱ dөng nó tӯ
cӫa bҥn ngҳt xӱ lý-điӅu này hҥn chӃ các chӭc năng mà ta có th Ӈ gӑi tӯ mӝt ngҳt xӱ lý.

Ngӳ cҧnh ngҳt thӡi gian là quan tr ӑng bӣi vì các bӝ xӱ lý ngҳt ngҳt mã khác.

Mã nên đưӧc nhanh chóng và đ ơn giҧn. Bұn vòng lһp là có thӇ, nhưng khuyӃn khích. Đây
là mӝt điӇm quan trӑng, luôn luôn ghi nh ӟ rҵng xӱ lý ngҳt cӫa bҥn đã ngҳt mã khác (thұm
chí có thӇ xӱ lý mӝt ngҳt trên mӝt dòng khác nhau!). B ӣi vì điӅu này bҧn chҩt không đӗng
bӝ, bҳt buӝc tҩt cҧ các bӝ xӱ lý ngҳt như nhanh chóng và đ ơn giҧn nhҩt có thӇ càng nhiӅu
càng tӕt, làm viӋc cҫn đưӧc đҭy ra tӯ bӝ xӱ lý ngҳt và

thӵc hiӋn trong mӝt nӱa dưӟi, chҥy vào thӡi gian thuұn tiӋn hơn.

Các thiӃt lұp cӫa ngăn xӃp mӝt bӝ xӱ lý ngҳt là mӝt lӵa chӑn cҩu hình. Trong l ӏch sӱ, ngҳt
xӱ lý không nhұn đưӧc ngăn xӃp riêng cӫa mình. Thay vào đó, h ӑ sӁ chia sҿ các ngăn xӃp
cӫa

quá trình mà h ӑ bӏ gián đoҥn. Các hҥt nhân ngăn x Ӄp là hai trang v Ӆ kích thưӟc, thông
thưӡng, đó là 8KB

trên 32-bit, kiӃn trúc và 16KB trên các ki Ӄn trúc 64-bit. Bӣi vì trong này thi Ӄt lұp ngҳt

xӱ lý chia sҿ đӕng, hӑ phҧi đưӧc đһc biӋt tiӃt kiӋm vӟi nhӳng dӳ liӋu hӑ phân bә

ӣ đó. Tҩt nhiên, hҥt nhân ngăn x Ӄp đưӧc giӟi hҥn đӇ bҳt đҫu, vì vұy tҩt cҧ mã hҥt nhân nên
đưӧc

thұn trӑng.

Sӟm trong quá trình h ҥt nhân 2.6, tùy chӑn đã đưӧc bә sung đӇ làm giҧm kích thưӟc cӫa
hai ngăn x Ӄp

trang xuӕng mӝt, cung cҩp chӍ là mӝt 4KB ngăn xӃp trên hӋ thӕng 32-bit. Áp lӵc này giҧm trí
nhӟ bӣi vì mӛi quá trình trên h Ӌ thӕng trưӟc đây cҫn hai trang cӫa kӅ nhau, bӝ nhӟ hҥt
nhân nonswappable. Đ Ӈ đӕi phó vӟi các kích thưӟc ngăn xӃp giҧm, xӱ lý ngҳt đưӧc cho
riêng ngăn x Ӄp cӫa hӑ, mӝt ngăn xӃp trên bӝ vi xӱ lý, mӝt trang trong kích thưӟc. ngăn xӃp
này đưӧc gӑi là ngҳt ngăn xӃp. Mһc dù kích thưӟc tәng cӝng cӫa các ngҳt ngăn xӃp là mӝt
nӱa cӫa

ban đҫu đưӧc chia sҿ ngăn xӃp, ngăn xӃp trung bình không gian có s ҹn là lӟn hơn bӣi vì
ngҳt xӱ lý

có đưӧc trang đҫy đӫ bӝ nhӟ cho bҧn thân mình.

Xӱ lý ngҳt cӫa bҥn không nên quan tâm nh ӳng gì ngăn x Ӄp thiӃt lұp đưӧc sӱ dөng hoһc
nhӳng gì kích thưӟc cӫa hҥt nhân ngăn xӃp có. Luôn luôn s ӱ dөng mӝt sӕ lưӧng tӕi thiӇu
tuyӋt đӕi ngăn xӃp không gian.

Thӵc hiӋn xӱ lý ngҳt

Có lӁ không đáng ngҥc nhiên, viӋc thӵc hiӋn hӋ thӕng xӱ lý ngҳt trong Linux là ki Ӄn trúc phө
thuӝc. Thӵc hiӋn phө thuӝc vào bӝ vi xӱ lý, loҥi ngҳt

điӅu khiӇn đưӧc sӱ dөng, và thiӃt kӃ cӫa kiӃn trúc và máy. Hình 7.1 là bi Ӈu đӗ cӫa con
đưӡng ngҳt mӝt có thông qua phҫn cӭng và hҥt nhân.

A tuan chen them hinh vao nhe!

Mӝt vҩn đӅ thiӃt bӏ ngҳt bҵng cách gӱi mӝt tín hiӋu điӋn trên xe buýt cӫa mình cho các gián
đoҥn điӅu khiӇn. NӃu yêu cҫu ngҳt đưӧc kích hoҥt (có thӇ là đeo mһt nҥ ra), bӝ điӅu khiӇn
ngҳt gӱi ngҳt đӇ xӱ lý. Trong hҫu hӃt các kiӃn trúc, điӅu này đưӧc thӵc hiӋn bӣi mӝt tín
hiӋu điӋn đưӧc gӱi trong mӝt pin đһc biӋt đӇ xӱ lý. Trӯ khi ngҳt bӏ vô hiӋu hóa trong các b ӝ
vi xӱ lý (mà cũng có thӇ xҧy ra), xӱ lý ngay lұp tӭc dӯng lҥi nhӳng gì nó đang làm gì, vô
hiӋu hóa hӋ thӕng ngҳt, và nhҧy đӃn mӝt đӏa điӇm đӏnh sҹn trong bӝ nhӟ và thӵc thi các mã
nҵm ӣ đó. ĐiӇm này đưӧc xác đӏnh trưӟc đưӧc thiӃt lұp bӣi hҥt nhân và là điӇm mҩu chӕt
cho bӝ xӱ lý ngҳt.

Các ngҳt hành trình trong nhân b ҳt đҫu vào thӡi điӇm này nhұp cҧnh đưӧc xác đӏnh trưӟc,
cũng giӕng như

các cuӝc gӑi vào hӋ thӕng hҥt nhân thông qua m ӝt bӝ xӱ lý ngoҥi lӋ đưӧc xác đӏnh trưӟc.
Đӕi vӟi mӛi yêu cҫu ngҳt, bӝ xӱ lý nhҧy đӃn mӝt đӏa điӇm duy nhҩt trong bӝ nhӟ và thӵc thi
các mã nҵm ӣ đó. Theo cách này, h ҥt nhân biӃt sӕ IRQ cӫa ngҳt đӃn. Các điӇm vào ban
đҫu chӍ đơn giҧn là lưu gi trӏ này và lưu trӳ các giá trӏ đăng ký hiӋn tҥi (thuӝc nhiӋm vө
ngҳt) trên ngăn x Ӄp, sau đó nhân các cu ӝc gӑi do_IRQ (). Tӯ đây trӣ đi, hҫu hӃt các mã xӱ
lý ngҳt đưӧc viӃt bҵng C, tuy nhiên, nó là

vүn còn phө thuӝc vào kiӃn trúc.

chӭc năng do_IRQ () đưӧc khai báo là

unsigned int do_IRQ (struct regs pt_regs)

Bӣi vì C gӑi nơi quy ưӟc chӭc năng lұp luұn ӣ trên cùng cӫa ngăn xӃp, cơ cҩu pt_regs
chӭa các giá trӏ đăng ký ban đҫu mà trưӟc đây đưӧc lưu trong cc thӫ tөc nhұp cҧnh lҳp
ráp. Bӣi vì các giá trӏ ngҳt cũng đưӧc lưu lҥi, do_IRQ () có thӇ giҧi nén nó. Sau khi yêu cҫu
ngҳt đưӧc tính toán, do_IRQ () th ӯa nhұn khi nhұn đưӧc ngҳt và vô hiӋu hóa cung cҩp ngҳt
trên đưӡng dây. Trên máy PC bình th ưӡng, các hoҥt đӝng này đưӧc xӱ lý bӣi
mask_and_ack_8259A ().

TiӃp theo, do_IRQ () đҧm bҧo cho mӝt bӝ xӱ lý hӧp lӋ đưӧc đăng ký trên đưӡng dây và
rҵng đó là

kích hoҥt và hiӋn tҥi không thӵc hiӋn. NӃu vұy, nó gӑi handle_IRQ_event (), đ ưӧc đӏnh
nghĩa trong

kernel / irq / handler.c, đӇ chҥy cài đһt xӱ lý ngҳt cho đưӡng dây.

/**

* handle_IRQ_event - irq action chain handler

* @irq: the interrupt number

* @action: the interrupt action chain for this irq

* Handles the action chain of an irq event

*/

irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)

{
irqreturn_t ret, retval = IRQ_NONE;

unsigned int status = 0;

if (!(action->flags & IRQF_DISABLED))

local_irq_enable_in_hardirq();

do {

trace_irq_handler_entry(irq, action);

ret = action->handler(irq, action->dev_id);

trace_irq_handler_exit(irq, action, ret);

switch (ret) {

case IRQ_WAKE_THREAD:

/*

* Set result to handled so the spurious check

* does not trigger.

*/

ret = IRQ_HANDLED;

/*

* Catch drivers which return WAKE_THREAD but

* did not set up a thread function

*/

if (unlikely(!action warn_no_thread(irq, action);

break;

/*

* Wake up the handler thread for this

* action. In case the thread crashed and was

* killed we just pretend that we handled the

* interrupt. The hardirq handler above has

* disabled the device interrupt, so no irq


* storm is lurking.

*/

if (likely(!test_bit(IRQTF_DIED,

&action->thread_flags))) {

set_bit(IRQTF_RUNTHREAD, &action ->thread_flags);

wake_up_process(action ->thread);

/* Fall through to add to randomness */

case IRQ_HANDLED:

status |= action->flags;

break;

default:

break;

retval |= ret;

action = action ->next;

} while (action);

if (status & IRQF_SAMPLE_RANDOM)

add_interrupt_randomness(irq);

local_irq_disable();

return retval;

Trưӟc tiên, vì bӝ xӱ lý ngҳt vô hiӋu hóa, chúng đang quay tr ӣ lҥi trӯ khi

IRQF_DISABLED đã đưӧc quy đӏnh trong quá trình đăng ký c ӫa bӝ xӱ lý. Nhӟ lҥi rҵng

IRQF_DISABLED xác đӏnh rҵng xӱ lý phҧi đưӧc chҥy vӟi ngҳt vô hiӋu hóa. TiӃp theo,

mӛi xӱ lý tiӅm năng đưӧc thӵc hiӋn trong mӝt vòng lһp. NӃu dòng này không đ ưӧc chia sҿ,
vòng lһp kӃt thúc sau khi l һp đi lһp lҥi đҫu tiên. NӃu không, tҩt cҧ các bӝ xӱ lý đưӧc thӵc thi.
Sau đó,

add_interrupt_randomness () đ ưӧc gӑi là nӃu IRQF_SAMPLE_RANDOM đưӧc quy đӏnh


trong quá trình đăng ký. Ch ӭc năng này sӱ dөng thӡi gian cӫa các ngҳt đӇ tҥo ra dӳ liӋu
ngүu nhiên cho các máy phát đi Ӌn sӕ ngүu nhiên. Cuӕi cùng, ngҳt đưӧc mӝt lҫn nӳa vô
hiӋu hóa (do_IRQ () hy v ӑng hӑ vүn còn phҧi đưӧc tҳt) và hàm trҧ vӅ. Trӣ lҥi do_IRQ (),
chӭc năng dӑn dҽp và trҧ vӅ cho điӇm vào ban đҫu, sau đó nhҧy đӃn ret_from_intr ().

Các ret_from_intr () là th ưӡng, như vӟi mã mөc ban đҫu, đưӧc viӃt trong lҳp ráp.

ĐiӅu này thưӡng xuyên kiӇm tra xem liӋu mӝt lӏch lҥi là chӡ. (Nhӟ lҥi tӯ Chương 4, "Quy
trnh

Lұp kӃ hoҥch, "điӅu này có nghĩa là need_resched đ ưӧc thiӃt lұp). NӃu mӝt lӏch lҥi là chӡ,
và các hҥt nhân đang tr ӣ lҥi vӟi không gian sӱ dөng (có nghĩa là, nh ӳng gián đoҥn ngҳt mӝt
quá trình ngưӡi dùng), lӏch () đưӧc gӑi. NӃu hҥt nhân đang tr ӣ lҥi vӟi không gian hҥt nhân
(có nghĩa là, nhӳng gián đoҥn bӏ gián đoҥn trong bҧn thân), lӏch () đưӧc gӑi là chӍ khi
preempt_count là s ӕ không. NӃu không nó không ph ҧi là an toàn Ð Ӈ tránh bӏ hҥt nhân. Sau
khi lӏch trình () trҧ vӅ, hoһc nӃu không có công viӋc đang chӡ, sә đăng ký ban đҫu đưӧc
phөc hӗi và các hӗ sơ hҥt nhân bҩt cӭ điӅu gì bӏ ngҳt.

Trên x86, các thói quen l ҳp ráp ban đҫu đưӧc đһt tҥi arch/x86/kernel/entry_64.S

(entry_32.S cho 32 -bit x86) và các phương php C ưӧc đһt tҥi arch/x86/kernel/irq.c.

KiӃn trúc khác có hӛ trӧ tương tӵ.

/ proc / interrupts

Procfs là mӝt hӋ thӕng tұp tin ҧo chӍ tӗn tҥi trong bӝ nhӟ hҥt nhân và thưӡng đưӧc gҳn ӣ
proc /. Đӑc hoһc viӃt các tұp tin trong procfs g ӑi chӭc năng hҥt nhân mà mô phӓng đӑc hoһc
ghi tӯ mӝt tұp tin thӵc sӵ. Mӝt ví dө liên quan đưӧc các / proc / interrupts t ұp tin, mà là dân
cư vӟi sӕ liӋu thӕng kê liên quan đ Ӄn ngҳt trên hӋ thӕng. Đây là mүu đҫu ra tӯ mӝt máy tính
uniprocessor:

CPU0

0: 3602371 XT -PIC timer

1: 3048 XT-PIC i8042

2: 0 XT-PIC cascade

4: 2689466 XT -PIC uhci-hcd, eth0

5: 0 XT-PIC EMU10K1

12: 85077 XT -PIC uhci-hcd

15: 24571 XT -PIC aic7xxx

NMI: 0

LOC: 3602236

ERR: 0
Cӝt đҫu tiên là yêu cҫu ngҳt. Trên hӋ thӕng này, ngҳt đánh sӕ 0-2, 4, 5, 12,

và 15 có mһt. Xӱ lý không đưӧc cài đһt trên các tuyӃn đưӡng không đưӧc hiӇn thӏ. Cӝt thӭ
hai là truy cұp cӫa sӕ ngҳt received.A cӝt là hiӋn nay cho mӛi bӝ vi xӱ lý trên hӋ thӕng,
nhưng my ny chӍ có mӝt processor.As bҥn có thӇ thҩy, nhӳng ngҳt giӡ đã nhұn đưӧc
3.602.371 ngҳt, 2 trong khi các card âm thanh (emu10k1) đã nh ұn đưӧc không (đó là mӝt
dҩu hiӋu cho thҩy nó không đưӧc sӱ dөng tӯ máy tính khӣi đӝng). Cӝt thӭ ba là bӝ điӅu
khiӇn xӱ lý ngҳt ngҳt này. XT-PIC tương ӭng vӟi các tiêu chuҭn

PC lұp trình điӅu khiӇn ngҳt. Trên hӋ thӕng vӟi mӝt I / O APIC, hҫu hӃt các ngҳt

có danh sách IO-APIC cҩp hoһc IO-APIC cҥnh là bӝ điӅu khiӇn ngҳt cӫa hӑ. Cuӕi cùng, cӝt
cuӕi cùng là thiӃt bӏ liên quan ngҳt này. Tên này đưӧc cung cҩp bӣi các tham sӕ devname
đӇ request_irq (), nhưưӧc thҧo luұn trưӟc đó. NӃu ngҳt đưӧc chia sҿ, như l trưӡng hӧp
vӟi sӕ gián đoҥn 4 trong ví dө này, tҩt cҧ các thiӃt bӏ đã đăng ký trên yêu cҫu ngҳt đưӧc liӋt
kê.

Đӕi vӟi nhӳng ngưӡi tò mò, mã procfs nҵm chӫ yӃu trong fs / proc. Các ch ӭc năng cung
cҩp / proc / interrupts là, không đáng ng ҥc nhiên, kiӃn trúc phө thuӝc và đһt tên là
show_interrupts ().

Các hҥt nhân Linux th ӵc thi mӝt hӑ vӅ các giao diӋn cho các thao tác trҥng thái ngҳt trên
máy. Các giao di Ӌn này cho phép b ҥn vô hiӋu hóa hӋ thӕng ngҳt cho các bӝ xӱ lý hiӋn hành
hoһc che đi mӝt đưӡng dây ngҳt cho toàn bӝ máy. Nhӳng thưӡng trình này ph ө thuӝc tҩt cҧ
các cҩu trúc và có thӇ đưӧc tìm thҩy trong <asm/system.h> và <asm/irq.h>. Xem B ҧng 7.2,
sau đó trong chương ny, ӕi vӟi mӝt danh sách đҫy đӫ các giao diӋn. Lý do đӇ kiӇm soát
các hӋ thӕng ngҳt nói chung c ҫn phҧi cung cҩp đӗng bӝ hóa. Bҵng cách vô hiӋu hoá ngҳt,
bҥn có thӇ đҧm bҧo rҵng mӝt bӝ xӱ lý sӁ không tránh ngҳt mã hiӋn tҥi cӫa bҥn. Hơn nӳa,
vô hiӋu hoá ngҳt cũng vô hiӋu hóa hҥt nhân. Không phân ph ӕi vô hiӋu hóa ngҳt hay viӋc vô
hiӋu hóa hҥt nhân cung cҩp bҩt kǤ sӵ bҧo vӋ tӯ viӋc truy cұp đӗng thӡi tӯ các bӝ vi xӱ lý
khác, tuy nhiên. B ӣi vì Linux hӛ trӧ nhiӅu bӝ xӱ lý, mã hҥt nhân nói chung c ҫn phҧi có đưӧc
mӝt sӕ loҥi khóa đӇ ngăn ngӯa mӝt bӝ xӱ lý truy cұp dӳ liӋu đưӧc chia sҿ cùng mӝt lúc.
Các khóa này thưӡng đưӧc kӃt hӧp vӟi viӋc vô hiӋu hóa ngҳt cөc bӝ. Khóa này cung cҩp
bҧo vӋ chӕng truy cұp đӗng thӡi tӯ các bӝ vi xӱ lý khác, trong khi vô hi Ӌu hoá ngҳt cung cҩp
bҧo vӋ chӕng lҥi các truy cұp đӗng thӡi tӯ mӝt trình xӱ lý ngҳt có thӇ.

Vô hiӋu hóa và kích hoҥt ngҳt

ĐӇ ngҳt vô hiӋu hóa cөc bӝ cho các bӝ xӱ lý hiӋn tҥi (và chӍ có bӝ xӱ lý hiӋn hành) và sau
đó bұt lҥi chúng, làm như sau:
local_irq_disable (); / ng ҳt * là vô hiӋu hoá .. * / local_irq_enable ();

Các chӭc năng này thưӡng đưӧc thӵc hiӋn như mӝt hoҥt đӝng lҳp ráp đơn lҿ. (Tҩt nhiên,
điӅu này phө thuӝc vào kiӃn trúc.) Thұt vұy, trên x86, local_irq_disable () là m ӝt
local_irq_enable cliand đ ơn giҧn () là mӝt chӍ dүn đơn giҧn. cli và sti đang l ҳp ráp các cuӝc
gӑi đӃn rõ ràng và thi Ӄt lұp cho phép ngҳt lá cӡ, tương ӭng. Nói cách khác, hӑ vô hiӋu hoá
và cho phép phân ph ӕi gián đoҥn vào bӝ xӱ lý phát hành.

Các local_irq_disable () th ưӡng là nguy hi Ӈm nӃu ngҳt đã bӏ vô hiӋu hoá trưӟc khi gӑi cӫa
nó. Các cuӝc gӑi tương ӭng vӟi local_irq_enable () v ô điӅu kiӋn cho phép ngҳt, bҩt chҩp
thӵc tӃ rҵng hӑ đã tҳt đӇ bҳt đҫu. Thay vào đó, cơ chӃ cҫn thiӃt đӇ khôi phөc các ngҳt vӅ
trҥng thái trưӟc. Đây là mӝt mӕi quan tâm chung vì m ӝt con đưӡng mã đưӧc đưa ra trong
hҥt nhân có thӇ đҥt đưӧc cҧ hai có và không có các ng ҳt kích hoҥt, tùy thuӝc vào chuӛi gӑi.
Ví dө, hãy tưӣng tưӧng các đoҥn mã trưӟc đây là mӝt phҫn cӫa mӝt chӭc năng lӟn hơn.
Hy tưӣng tưӧng rҵng chӭc năng này đưӧc gӑi bҵng hai chӭc năng khác, mӝt trong đó vô
hiӋu hóa ngҳt và mӝt không. Bӣi vì nó đang tr ӣ nên khó khăn hơn như l hҥt nhân phát
triӇn vӅ quy mô và phӭc tҥp đӇ biӃt tҩt cҧ các đưӡng dүn mã dүn đӃn mӝt chӭc năng, nó là
an toàn hơn nhiӅu đӇ lưu trҥng thái cӫa hӋ thӕng ngҳt trưӟc khi vô hiӋu hóa nó sau, khi b ҥn
đã sҹn sàng đӇ ngҳt bұt lҥi , bҥn chӍ cҫn khôi phөc lҥi tình trҥng ban đҫu cӫa chúng:

local_irq_save (c ӡ); / * ngҳt bây giӡ bӏ vô hiӋu hóa * /

local_irq_restore (c ӡ); / ngҳt là khôi phөc lҥi trҥng thái trưӟc đó cӫa chúng * /

Lưu
rҵng nhӳng phương php ny ưӧc thӵc hiӋn ít nhҩt mӝt phҫn như cc macro, v
thӃ cӡ tham sӕ là có vҿ như thng qua gi  trӏ. Tham sӕ này có chӭa dӳ liӋu cө thӇ cҩu trúc
có chӭa các trҥng thái cӫa các hӋ thӕng ngҳt. Bӣi vì ít nhҩt mӝt hӛ trӧ cҩu trúc kӃt hӧp
ngăn xӃp thông tin vào giá tr ӏ (ahem, SPARC), cӡ không thӇ đưӧc thông qua chӭc năng
khác (đһc biӋt, nó phҧi đưӧc giӳ trên cùng mӝt khung ngăn xӃp). Vì lý do này, các cuӝc gӑi
đӇ lưu lҥi và ngҳt cuӝc gӑi đӇ khôi phөc lҥi phҧi xҧy ra trong cùng chӭc năng.

Tҩt cҧ các chӭc năng trưӟc đây có thӇ đưӧc gӑi tӯ cҧ hai bӕi cҧnh ngҳt và quá trình.

No More Global cli()

Các hҥt nhân trưӟc đây là cung cҩp mӝt phương php Ӈ ngҳt vô hiӋu hóa trên tҩt cҧ các
bӝ vi xӱ lý trong hӋ thӕng. Hơn nӳa, nӃu mӝt bӝ xӱ lý đưӧc gӑi là phương php ny, n sӁ
phҧi chӡ cho đӃn khi các ngҳt đưӧc kích hoҥt trưӟc khi tiӃp tөc. Chӭc năng này đưӧc đһt
tên là cli () và các cuӝc gӑi cho phép tương ӭng đưӧc đһt tên là sti ()-rҩt x86-trung tâm, mһc
dù đã có cho mӑi kiӃn trúc.

Các giao di Ӌn này đã bӏ phҧn đӕi trong suӕt thӡi gian 2,5, và do đó t ҩt cҧ các đӗng bӝ hóa
ngҳt hiӋn nay phҧi sӱ dөng mӝt sӵ kӃt hӧp kiӇm soát ngҳt cөc bӝ và quay ә khóa. ĐiӅu này
có nghĩa rҵng mã mà trưӟc đây chӍ phҧi các ngҳt vô hiӋu hóa toàn cҫu đӇ đҧm bҧo đӝc
quyӅn truy cұp lүn nhau đӇ chia sҿ dӳ liӋu bây giӡ cҫn phҧi làm viӋc nhiӅu hơn mӝt chút.
Trưӟc đây, ngưӡi viӃt trình điӅu khiӇn có thӇ giҧ đӏnh mӝt cli () đưӧc sӱ dөng trong xӱ lý
ngҳt cӫa hӑ và bҩt cӭ nơi no khc chia sҿ dӳ liӋu đưӧc truy cұp sӁ cung cҩp loҥi trӯ lүn
nhau. Các cli () g ӑi sӁ đҧm bҧo rҵng không có xӱ lý ngҳt khác (và do đó xӱ lý riêng cӫa hӑ)
sӁ chҥy. Hơn nӳa, nӃu mӝt bӝ xӱ lý vào mӝt cli () khu vӵc bҧo vӋ, nó sӁ không tiӃp tөc cho
đӃn khi xӱ lý ban đҫu đã thoát cli c ӫa nó () khu vӵc đưӧc bҧo vӋ vӟi mӝt cuӝc gӑi đӃn sti ().
Loҥi bӓ các cli toàn cҫu () có mӝt sӕ ít các lӧi thӃ. Đҫu tiên, nó buӝc ngưӡi viӃt điӅu khiӇn
đӇ thӵc hiӋn các khóa thӵc sӵ. Mӝt khóa xӱ lý mӛi gói vӟi mӝt mөc đích cө thӇ là nhanh
hơn mӝt khóa toàn cҫu, mà là hiӋu quҧ nhӳng gì cli () là. Th ӭ hai, viӋc loҥi bӓ đưӧc sҳp xӃp
rҩt nhiӅu mã trong hӋ thӕng ngҳt và di chuyӇn mӝt nhóm nhiӅu hơn nӳa. KӃt quҧ là đơn
giҧn và dӉ hiӇu

Vô hiӋu hóa mӝt yêu cҫu ngҳt cө thӇ

Trong phҫn trưӟc, chúng tôi đã vô hi Ӌu hóa tҩt cҧ các chӭc năng ngҳt cung cҩp cho mӝt cҧ
bӝ xӱ lý. Trong mӝt sӕ trưӡng hӧp, nó rҩt hӳu ích đӇ vô hiӋu hóa chӍ có mӝt dòng cө thӇ
ngҳt cho toàn bӝ hӋ thӕng. ĐiӅu này đưӧc gӑi là che đi mӝt đưӡng dây ngҳt. Ví dө, bҥn có
thӇ muӕn cung cҩp vô hiӋu hóa cӫa các ngҳt cӫa thiӃt bӏ trưӟc khi thao tác trҥng thái cӫa
nó. Linux cung cҩp bӕn giao diӋn cho công viӋc này:

void disable_irq (unsigned int irq);

void disable_irq_nosync (irq int không d ҩu);

void enable_irq (unsigned int irq);

void synchronize_irq (unsigned int irq);

Hai chӭc năng đҫu tiên đưӧc vô hiӋu hóa mӝt ngҳt dòng trong bӝ điӅu khiӇn ngҳt.

ĐiӅu này cung cҩp vô hiӋu hóa các ngҳt cung cҩp cho tҩt cҧ các bӝ vi xӱ lý trong hӋ
thӕng. Ngoài ra, các chӭc năng disable_irq () không tr ҧ lҥi cho đӃn khi xӱ lý bҩt kǤ hiӋn
đang thӵc hiӋn hoàn tҩt. Như vұy, các lӡi gӑi đưӧc đҧm bҧo rҵng không chӍ làm ngҳt mӟi
sӁ không đưӧc chuyӇn giao trên đưӡng nhҩt đӏnh, nhưng cng l bҩt kǤ bӝ xӱ lý đã đưӧc
thӵc hiӋn có kӃt thúc.Các chӭc năng disable_irq_nosync () không ch ӡ xӱ lý hiӋn tҥi đӇ hoàn
thành.

Các chӭc năng synchronize_irq () chӡ xӱ lý cө thӇ ngҳt đӇ thoát ra, nӃu nó là thӵc hiӋn,
trưӟc khi trӣ vӅ.

Các cuӝc gӑi đӃn các tә chӭc năng. Đӕi vӟi mӛi cuӝc gӑi đӃn disable_irq () ho һc
disable_irq_nosync () trên m ӝt đưӡng dây ngҳt nhҩt đӏnh, mӝt cuӝc gӑi tương ӭng vӟi
enable_irq ()

là bҳt buӝc. ChӍ trên các cuӝc gӑi cuӕi cùng đӇ enable_irq () là yêu cҫu ngҳt thӵc sӵ kích
hoҥt.

Ví dө, nӃu disable_irq () đ ưӧc gӑi là hai l ҫn, yêu cҫu ngҳt là không thӵc sӵ kích hoҥt lҥi cho
đӃn khi cuӝc gӑi thӭ hai đӃn enable_irq().

Tҩt cҧ ba cӫa các chӭc năng này có thӇ đưӧc gӑi tӯ thӡi điӇm ngҳt hoһc quá trình không
dӯng. NӃu gӑi tӯ thӡi điӇm ngҳt, hãy cҭn thұn! Bҥn không muӕn, ví dө, đӇ kích hoҥt mӝt
đưӡng dây ngҳt trong khi bҥn đang xӱ lý nó. (Hãy nhӟ rҵng các yêu cҫu ngҳt cӫa bӝ xӱ lý
đưӧc che đұy ra trong khi nó đang ph өc vө.)

Nó sӁ là khá thô sơӇ vô hiӋu hóa mӝt đưӡng dây ngҳt chia sҿ giӳa nhiӅu xӱ lý ngҳt. Vô
hiӋu hóa các dòng vô hi Ӌu hóa cung cҩp ngҳt cho tҩt cҧ các thiӃt bӏ trên dòng. Do đó, trình
điӅu khiӇn cho các thiӃt bӏ mӟi hơn c xu hưӟng không sӱ dөng các giao diӋn này. Bӣi vì
các thiӃt bӏ PCI có đӇ hӛ trӧ chia sҿyêu cҫu ngҳt bӣi đһc điӇm kӻ thuұt, hӑ không nên sӱ
dөng các giao diӋn này ӣ tҩt cҧ. Như vұy, disable_irq () và b ҥn bè đưӧc tìm thҩy thưӡng
xuyên hơn trong cc trnh iӅu khiӇn cho các thiӃt bӏ thӯa cũ, như cәng song song cӫa máy
tính.

Trҥng thái cӫa hӋ thӕng ngҳt

Nó thưӡng hӳu ích đӇ biӃt tình trҥng cӫa hӋ thӕng ngҳt (ví dө, đã ngҳt đưӧc kích hoҥt hay
vô hiӋu hóa) hoһc liӋu bҥn đang thӵc hiӋn trong bӕi cҧnh ngҳt.

Các irqs_disabled (), đưӧc đӏnh nghĩa trong <asm/system.h>, tr ҧ vӅ giá trӏ khác không nӃu
ngҳt hӋ thӕng trên bӝ vi xӱ lý cӫa đӏa phương l v hiӋu. NӃu không, nó trҧ vӅ sӕ không.

Hai macro, quy đӏnh tҥi <linux/hardirq.h>, cung c ҩp mӝt giao diӋn đӇ kiӇm tra hҥt nhân cӫa

bӕi cҧnh hiӋn nay. Chúng là

in_interrupt ()

in_irq ()

Các hӳu ích nhҩt là lҫn đҫu tiên: Nó trҧ vӅ giá trӏ khác không nӃu hҥt nhân đang th ӵc hiӋn
bҩt kǤ loҥi xӱ lý ngҳt. ĐiӅu này bao gӗm cҧ thӵc hiӋn mӝt bӝ xӱ lý ngҳt hoһc nӱa dưӟi xӱ
lý. Các in_irq () trҧ vӅ giá trӏ khác không chӍ khi các hҥt nhân là cө thӇ thӵc hiӋn mӝt bӝ xӱ lý
ngҳt.

Thưӡng xuyên hơn, bҥn muӕn kiӇm tra xem bҥn đang ӣ trong bӕi cҧnh quá trình Đó là,. b ҥn
muӕn đӇ đҧm bҧo bҥn không phҧi là trong bӕi cҧnh ngҳt. ĐiӅu này thưӡng xҧy ra vì mã
muӕn làm mӝt cái gì đó mà chӍ có thӇ đưӧc thӵc hiӋn tӯ bӕi cҧnh quá trình, ch ҷng hҥn như
ngӫ. NӃu in_interrupt () tr ҧ vӅ sӕ không, hҥt nhân là trong b ӕi cҧnh quá trình. Có, tên là khó
hiӇu và không làm gì đ Ӈ truyӅn đҥt ý nghĩa cӫa chúng. Bҧng 7.2 là mӝt bҧn tóm tҳt

các phương php kiӇm soát ngҳt và mô tҧ cӫa hӑ.

Table 7.2 Interrupt Control Methods

Function Description

local_irq_disable() Disables local interrupt delivery

local_irq_enable() Enables local interrupt delivery

local_irq_save() Saves the current state of local interrupt delivery and then disables
it

local_irq_restore() Restores local interrupt delivery to the given state

disable_irq() Disables the given interrupt line and ensures no handler on the line is
executing before returning

disable_irq_nosync() Disables the given interrupt line

enable_irq() Enables the given interrupt line


irqs_disabled() Returns nonzero if local interrupt delivery is disabled; otherwise

returns zero

in_interrupt() Returns nonzero if in interrupt conte xt and zero if in process context

in_irq() Returns nonzero if currently executing an interrupt handler and zero


otherwise

KӃt luұn:

Chương ny xem x t ngҳt, mӝt nguӗn tài nguyên phҫn cӭng đưӧc sӱ dөng bӣi các thiӃt bӏ
không đӗng bӝ tín hiӋu bӝ vi xӱ lý. Ngҳt, có hiӋu lӵc, đưӧc sӱ dөng bӣi phҫn cӭng đӇ làm
gián đoҥn hӋ điӅu hành.

Hҫu hӃt các phҫn cӭng hiӋn đҥi sӱ dөng ngҳt đӇ giao tiӃp vӟi hӋ điӅu hành. Các thiӃt bӏ
điӅu khiӇn đӇ quҧn lý mӝt phҫn nhҩt đӏnh cӫa phҫn cӭng đăng ký mӝt bӝ xӱ lý gián đoҥn đӇ
đáp ӭng và làm gián đo ҥn quá trình phát hành t ӯ phҫn cӭng liên quan c ӫa chung. Công tác
thӵc hiӋn trong ngҳt bao gӗm xác nhұn và cài đһt lҥi phҫn cӭng, sao chép dӳ liӋu tӯ thiӃt bӏ
vào bӝ nhӟ chính và ngưӧc lҥi, xӱ lý các yêu cҫu phҫn cӭng, và đưa ra cc yîu cҫu phҫn
cӭng mӟi.

Hҥt nhân cung cҩp giao di Ӌn cho đăng ký và huӹ đăng ký xӱ lý gián đoҥn, vô hiӋu hóa ngҳt,
che ra đưӡng gây cҧn trӣ, và kiӇm tra tình trҥng cӫa hӋ thӕng gián đoҥn. Bҧng 7.2 cung cҩp
mӝt cái nhìn tәng quan cӫa nhiӅu các chӭc năng này.

Bӣi vì làm gián đoҥn mã gián đoҥn thӵc hiӋn các (quy trình, hҥt nhân chính nó, và th ұm chí
xӱ lý các gián đoҥn), hӑ phҧi thӵc thi mӝt cách nhanh chóng. Thông th ưӡng, tuy nhiên, có
rҩt nhiӅu viӋc phҧi làm. ĐӇ cân đӕi sӕ lưӧng lӟn công viӋc vӟi sӵ cҫn thiӃt đӇ thӵc hiӋn
nhanh chóng, h ҥt nhân phân chia công vi Ӌc cӫa các ngҳt xӱ lý thành hai n ӱa. ViӋc xӱ lý
gián đoҥn, nӱa trên, đã đưӧc thҧo luұn trong chương ny. Cc chương tiӃp theo nhìn vào
nӱa dưӟi.

You might also like