stivuitoare de întrerupere
Funcția care efectuează nucleul ca răspuns la o anumită întrerupere este numit handler de întrerupere (handler de întrerupere) il și rutina de serviciu de întrerupere (întrerupere serviciu de rutină). Fiecare dispozitiv care generează întrerupere corespunde unui handler de întrerupere. De exemplu, o funcție mânerele întrerupe cronometrul sistemului, iar celălalt - o întrerupere generată de tastatură. Un handler de întrerupere pentru un dispozitiv face parte dintr-un dispozitiv de conducător auto - cod kernel care controlează dispozitivul.
În sistemul de operare Linux întrerupe manipulare - este functiile normale. scris în limbajul de programare C și el trebuie să respecte anumite stadiul tehnicii pentru kernel-ul poate într-un mod standard de a primi informații despre procesor, dar ostalnom- functiile normale. Singurul lucru care distinge handlerele întrerupere de alte funcții de bază - asta e ceea ce ei sunt numite de către nucleu, ca răspuns la întrerupere și se execută într-un context special, numit contextul de întrerupere (context întrerupere), care va fi discutat mai târziu.
Deoarece o întrerupere poate avea loc în orice moment, apoi, respectiv, iar conductorul de întrerupere poate fi apelat în orice moment. Este imperios necesar ca handlerul de întreruperi este foarte rapid, și a reluat controlul asupra codului întrerupt cât mai repede posibil. Prin urmare, cu toate că hardware-ul și este important ca întreruperea este servit imediat, este important pentru restul sistemului de a întrerupe manipulant executate în cel mai scurt timp posibil. Munca minimă posibil ca are de a face un handler de întrerupere - este de a trimite un dispozitiv de confirmare care intrerup este primit. De obicei, cu toate acestea, stivuitoare de întrerupere trebuie să efectueze mai mult de lucru. De exemplu, ia în considerare un handler de întrerupere a dispozitivului de rețea. Odată cu trimiterea confirmării hardware, rutina de tratare a întreruperii ar trebui să copieze pachetele de rețea de pe un dispozitiv hardware în memoria sistemului, să le proceseze, trimite stiva de protocol corespunzător sau programul corespunzător. Este evident că acest lucru necesită o mulțime de muncă.
superioare și inferioare jumatatile
Este clar că aceste două cerințe pe care handlerul de întrerupere trebuie să fie efectuate rapid și, în plus, pentru a efectua o mulțime de muncă, sunt contradictorii. Datorită cerințelor contradictorii, rutina de tratare a întreruperii este împărțit în două părți sau jumătăți. handler de întrerupere este jumătatea superioară (partea de sus) - se efectuează imediat după primirea întreruperii și efectuează o lucrare, întârziere critică în timp, cum ar fi trimiterea o confirmare de primire a întreruperii sau a reseta dispozitivul hardware. Lucrările care se efectuează mai târziu, se depune înainte ca partea de jos (sau primar) jumătate (jumătate de jos). Jumătatea inferioară este procesat mai târziu, într-un moment mai convenabil, atunci când toate întreruperile sunt activate. Destul de des, jumătatea de jos este executată imediat după revenirea din rutina de tratare a întreruperii.
Sistemul de operare oferă o varietate de mecanisme de punere în aplicare, prelucrarea jumătăților inferioară, care sunt discutate în Capitolul 7, „Manipularea jumătatea inferioară și acțiunea amânată.“
Luați în considerare exemplul unei rutine de tratare a întreruperii pentru separarea jumătății superioare și inferioare prin NIC simplu vechi. Când adaptorul de interfață de rețea recepționează pachetele primite de la rețea, acesta trebuie să notifice kernel-ul care sunt disponibile date noi. Acest lucru trebuie făcut imediat, în scopul de a obține lățimea de bandă optimă și latență la transferul informațiilor în rețea. Prin urmare, o întrerupere este generată imediat: „Hei, există pachete de kernel proaspete de nucleu răspunde prin efectuarea de tratare a întreruperii înregistrat de la adaptorul de curent alternativ!..
Un handler de întrerupere este executat, hardware rutate pachetele de confirmare sunt copiate în memoria principală, și după aceea adaptorul de curent alternativ este pregătit să primească noi pachete. Această sarcină este un important și critic pentru timpul de execuție și specifice pentru fiecare tip de hardware. Restul de procesare de pachete de rețea se realizează mai târziu - în partea de jos handler jumătate de întrerupere. În acest capitol considerăm prelucrarea jumătatea superioară, iar următorul - inferior.
Înregistrează-handler de întrerupere
întrerupe pentru stivuitoare responsabilitatea driverele de dispozitiv care gestionează un anumit tip de hardware. Fiecare driver de dispozitiv este conectat, iar în cazul în care dispozitivul utilizează o întrerupere (și cel mai utilizat), conducătorul auto trebuie să efectueze înregistrarea handler de întrerupere.
Conducătorul auto poate înregistra rutina de tratare a întreruperii pentru procesarea liniei specificate cu următoarele funcții.
/ * Request_irq: aloca o anumită linie de întrerupere * /
int request_irq (unsigned int irq,
irqreturn_t (* handler) (int, void *, pt_regs struct *), irqflags lungi fără semn,
char const * devname,
Primul parametru, irq. puncte atribuit numărul de întrerupere. Pentru unele dispozitive, cum ar fi, de exemplu, un convențional dispozitive de calculator personal, cronometru și tastatură, această valoare este de obicei fixat rigid. Pentru majoritatea celorlalte dispozitive, această valoare este determinată prin testarea (sondare) sau alt mod dinamic.
Al doilea parametru, handler. - un pointer la o funcție de tratare a întreruperii, care servește această întrerupere. Această funcție se numește atunci când sistemul de operare vine întrerupere. Se atrage atenția asupra unui prototip specific al handler. Este nevoie de trei parametri și returnează un tip de valoare irqreturn_t. Mai târziu, în acest capitol vom discuta mai în detaliu funcția.
Al treilea parametru, irqflags. Acesta poate fi zero sau cuprind o bitmask cu una sau mai multe dintre următoarele steaguri.
• SA_INTERRUPT. Acest pavilion indică faptul că rutina de tratare a întreruperii - un bystryyobrabotchikpreryvaniya. Sistemul Istoricheskitakslozhilos, chtooperatsionnaya Linux distinge între manipulare de întrerupere lente și rapide. Este de așteptat ca cele mai rapide procesoare sunt rapide, dar potential foarte des, astfel încât comportamentul handler de întrerupere este modificat pentru a furniza viteza maximă posibilă de punere în aplicare. Astăzi există doar o singură diferență: atunci când rutina de tratare a întreruperii rapide dezactivează toate întreruperile de pe procesor local. Acest lucru permite final rapid la handler rapid, și alte întreruperi în orice mod care nu este pometat. În mod implicit (în cazul în care acest lucru nu este specificat) a permis toate întreruperile, cu excepția celor mascate pe toate procesoarele și manipulatorii care se execută în prezent. Pentru toate întreruperile cu excepția întrerupere timer, nu este necesar să se stabilească acest pavilion.
• SA_SAMPLE_RANDOM. Acest pavilion indică faptul că întreruperea generată de acest aparat, ar trebui să contribuie la piscina entropie nucleu. Kernel piscina entropie oferă generarea de numere aleatoare adevărate pe baza diferitelor evenimente aleatoare. În cazul în care este specificat acest pavilion, momentele când au venit întrerupere, vor fi introduse în piscina entropie. Acest flag nu poate fi setat dacă dispozitivul generează o întrerupere uneori previzibil (cum ar fi cronometrul sistem) sau dispozitiv atacator extern (cum ar fi un dispozitiv de rețea) pot fi influențate. Pe de altă parte, cele mai multe dispozitive generează întreruperi în momente imprevizibile și, prin urmare, sunt o sursă bună de entropie. Pentru o descriere mai detaliată a piscinei entropiei kernel vezi. Anexa B, „Generatorul de numere aleatoare a nucleului.“
• SA_SHIRQ. Acest pavilion indică faptul că numărul de întreruperi pot fi partajate de mai multe stivuitoare de întrerupere (partajat). Fiecare handler, care este înregistrată pe aceeași linie de întrerupere, steagul trebuie să indice acest lucru. În caz contrar, doar un singur handler de întrerupere poate exista pentru fiecare linie. Pentru mai multe informații despre stivuitoare de întrerupere partajate, consultați secțiunea următoare.
Al patrulea parametru, devname, - acesta este ASCII-string care descrie care dispozitivul este conectat la întreruperea. De exemplu, pentru a întrerupe tastatura PC-ul, valoarea este „tastatură“. nume de dispozitive Word sunt utilizate pentru utilizator prin intermediul unor interfețe de interacțiune
/ Proc / ir q și / proc / întrerupe. care vor fi luate în considerare în curând.
Al cincilea parametru, Devid. utilizate în principal pentru linii de cerere de întrerupere partajate. Când handler de întrerupere este eliberat (descris mai jos), parametrul dev_id oferă un identificator unic (cookie), care permite eliminarea numai linia handler de întrerupere necesară. Fără această opțiune, ar fi imposibil să se determine kernel-ul ce handler de întrerupere a liniei trebuie să fie eliminate. În cazul în care linia de cerere și o întrerupere nu este partajat, este posibil ca acest parametru indică NULL, în cazul în care același număr de întrerupere este partajată, este necesar să se specifice un identificator unic (cookie) (în cazul în care dispozitivul nu este conectat la noroi ISA, cele mai multe dintre toate, Aceasta susține numărul de întrerupere în comun).
Acest parametru este, de asemenea, a trecut la rutina de tratare a întreruperii pentru fiecare apel. Practica obișnuită - un pointer la structura dispozitivului de transmisie (device context), deoarece acest parametru este unic și, în plus, poate fi util să existe un pointer la această structură într-un handler de întrerupere.
Daca va avea succes, q funcția request_ir () returnează zero. Valoarea returnata nenulă indică faptul că a apărut o eroare și de tratare a întreruperii specificat nu a fost înregistrată. Cele mai frecvente codul de eroare - -EBUSY această valoare, ceea ce indică faptul că linia de cerere de întrerupere este deja ocupată (și sau apelul curent sau primul apel nu a fost specificat pavilion SA_SHIRQ).
Trebuie remarcat faptul că funcția request_ir q () este în modul adormire (somn) și, în consecință, nu poate fi numit de context întrerupere, sau în alte situații în care codul nu poate fi blocat. O greșeală comună este credința că funcția request_irq (), puteți apela în condiții de siguranță, în cazurile în care nu poate merge într-o stare de repaus. Acest lucru este parțial din faptul că într-adevăr pur și simplu nu înțeleg de ce request_irq funcția () trebuie să se aștepte nimic. Lucru este. că înregistrarea are loc adăugarea de informații pe linia de întrerupere în directorul / proc / IRQ. Funcția proc_mkdir () este folosit pentru a crea noi elemente în procfs sistem de fișiere. Această funcție solicită funcția proc_creat e () pentru a crea noi elemente procfs sistem de fișiere. care, la rândul său, determină funcția kmalloc () pentru a aloca memorie. Așa cum va fi arătat în capitolul 11, „Managementul memoriei“, kmalloc () poate merge într-o stare de repaus. Acesta este modul în care!
Pentru handler întrerupe linia de înregistrare și de instalare a driverului în codul, puteți utiliza următorul apel.
în cazul în care (request_irq (irqn, my_interrupt, SA_SHIRQ, "my_device", dev))
printk (KERN_ERR "my_device: nu se poate înregistra IRQ \ n.", irqn);
În acest exemplu, parametrul IRQ n - este o cerere pentru numărul liniei de întrerupere solicitat, setarea my_interrup T - este procesorul linie de linie cerere de întrerupere pentru o întrerupere poate fi partajat, numele dispozitivului - „my_device“, dev - valoarea parametrului dev_id. În cazul în care un cod de eroare imprimă mesajul care a apărut o eroare, și se întoarce din funcția. Dacă funcția de logare returnează o valoare nulă, rutina de tratare a întreruperii este instalat cu succes. Din acel moment, rutina de tratare a întreruperii va fi invocat ca răspuns la o întrerupere de intrare. Este important să inițializa echipamentul și verificați handler de întrerupere în secvența corectă pentru a preveni posibilitatea unui handler de apel până când echipamentul nu a fost inițializat.
handler de întrerupere de exceptare
Pentru a elibera linia de întrerupere este necesară pentru a apela o funcție
void free_irq (nesemnate int IRQ, void * dev_id)
În cazul în care linia specificată nu este partajat, această funcție elimină handler și dezactivează linia de întrerupere. În cazul în care o linie de cerere de întrerupere este partajată, apoi îndepărtat handler parametrul dev_id corespunzător. cerere de întrerupere linie este, de asemenea, interzisă atunci când sunt dezlipite ultima handler. Acum înțeleg de ce este important de a transmite parametrul unic valoare dev_id. Când utilizați întrerupere partajată necesită un identificator unic pentru a distinge asociat cu un număr de întrerupere diferit de fiecare alte entități care operează și permite funcții free_irq () pentru a șterge handler corectă. În orice caz, valoarea unui parametru lipsit nu este egal cu NULL, atunci acesta trebuie să corespundă handler, care este eliminat.
Call free_irq () funcție trebuie să fie realizată din contextul procesului.
Tabelul 6.1. Listă de management de înregistrare funcții de întrerupere
q request_ir () Registrul specificat handler de întrerupere pentru o linie de întrerupere dată
f ree_ir q () Eliberați handlerul de întreruperi specificat. În cazul în care o linie de întrerupere nu mai este asociat cu nici un procesor, interdicția specificată linie de întrerupere