Viivästetty prosessikutsu, jonka pitäisi näkyä. Järjestelmä keskeyttää prosessorin latauksen. Tarkista Windowsin äänijärjestelmä

Onko prosessorisi ylikuormitettu? Järjestelmän keskeytykset ovat syyllisiä.

Syy siihen, että prosessori on ylikuormitettu lähes koko istunnon ajan, voi olla ns. järjestelmäkeskeytyksiä, mikä puolestaan ​​tarkoittaa, että ongelma on tietokoneeseen asennetussa laitteistossa tai näiden laitteiden ajureissa. Mutta varoitan sinua heti: edes tämän artikkelin määrä ei riitä tunnistamaan kaikkia syitä (ja erityisesti niiden ratkaisuvaihtoehtoja), miksi järjestelmäkeskeytykset tappavat Windowsin. Koska lähestymistapaa ongelmien etsimiseen monimutkaistaa paljon monimutkaisemman työkalun käyttö kuin tässä kuvattu.

Mitä ovat järjestelmäkeskeytykset ja kuinka voit yrittää selviytyä prosessorin ylikuormituksesta?

Järjestelmän keskeytykset näkyvät Task Managerissa järjestelmäprosessina, mutta itse asiassa ne eivät ole sellaisia. Tämä " " on vain edustava, ja se heijastaa prosessorin kuormitusta käytettäessä matalan tason keskeytyksiä. Se on olennainen osa Windowsia, et voi lopettaa prosessia. Huolimatta pahaenteisestä nimestä, järjestelmäkeskeytykset ovat pakollinen ja normaali osa CPU:n ja muiden laitteiden välistä vuorovaikutusta.

Keskeytysten syy (tarkemmin sanottuna ajoittain liian hidas toiminta) voi olla tietokoneesi sisällä olevat laitteet, asennetut ohjelmat ja joskus itse prosessori. Loppujen lopuksi järjestelmäkeskeytykset ovat tietynlainen vuorovaikutus ohjelman/laitteiston ja itse prosessorin välillä. Aina kun järjestelmään tulee ilmestyä uusi prosessi, prosessori pudottaa kaiken ja suorittaa tehtävän. Sillä ei ole väliä, napsauttiko käyttäjä hiirtä vai käynnistettiinkö prosessi aikataulun mukaan, tehtävä lisätään välittömästi suoritettavaan jonoon. Valmistuttuaan prosessori palaa edelliseen tilaan.

Kuten ymmärrät, järjestelmäkeskeytykset voivat hyvin viestiä järjestelmälle ja käyttäjälle, että tällä hetkellä jotkin laskelmat etenevät virheellä, mikä näkyy tämän "prosessin" vakavana prosessoriresurssien kulutuksena. Terveessä järjestelmässä järjestelmäkeskeytykset "kuluttavat" ENEMMÄN 2 % prosessorin kokonaistyöstä. Vaikka olen myös törmännyt prosessoreihin, joiden keskeytysaste on 3-10%%, kaikki riippuu kokoonpanosta. Mutta jos huomaat, että prosessori käyttää vähintään 5 - 10 % prosessointitehostaan ​​keskeytyksiä istunnosta toiseen, tämä on merkki siitä, että tietokoneessa on ongelmia.

Järjestelmä keskeyttää. Kuinka käsitellä korkeita lukemia?

Jokainen seuraavista vaiheista vaatii järjestelmän uudelleenkäynnistyksen. Ei siksi, että se olisi tavallista, vaan koska keskeytysongelmat ratkaistaan ​​usein yksinkertaisesti käynnistämällä Windows uudelleen.

  • KULJETTAJIA JA LISÄÄ KULJETTAJIA

Saksalainen apuohjelma on ensimmäinen työkalu, joka auttaa määrittämään, ovatko rikkinäiset ohjaimet syyllisiä prosessorin lataamiseen johtaneisiin järjestelmäkeskeytuksiin. DPC Latency Checker. Lataa se tästä linkistä:

Asennusta ei tarvita. Apuohjelman olemus on yksinkertainen. Käynnistämme ja aloitamme työskentelyn Windowsissa, kunnes järjestelmän keskeytykset alkavat häiritä meitä. Tässä on normaalisti toimivan kokoonpanon ikkuna:

Mutta tässä he alkavat näyttää itsensä:

Englanninkielisen kommenttikentän apuohjelma neuvoo menemään Laitehallintaan ja aloittamaan asteittain verkkolaitteiden, äänikorttien, USB-ohjaimien, laitteiden poistamisen käytöstä. bluetooth. Suosittelen kuuntelemaan. Tarkastele jokaisen sammutuksen jälkeen lähemmin Tehtävienhallintaa ja apuohjelman ikkunaa ja katso, miten järjestelmä reagoi laitteiden väliaikaiseen sammutukseen. Jatka irrottamalla kaikki ulkoiset laitteet: modeemit, ulkoiset asemat, flash-asemat. Ja jos jossain vaiheessa tapahtuu muutoksia parempaan, päätä päivittää laitteen ohjain. Mutta Windowsin käynnistysongelmien välttämiseksi on parempi olla poistamatta näitä laitteita käytöstä (nämä ohjaimet ovat elintärkeitä, mutta ne ovat myös ohjaimia, ja on täysin mahdollista, että joudut asentamaan emolevyn ohjaimet uudelleen kokonaisena pakettina, vain kuten kun asennat Windowsin kokonaan):

Ohjelma toimii samalla tavalla LatenssiMa

http://www.resplendence.com/downloads

Se vaatii asennuksen, mutta on myös ilmainen. Sen tehtävänä on etsiä ajuritiedostoja, joissa on paljon laskelmia, jotka kuluvat lykättyyn proseduurikutsuun (prosessi, jonka keskeytyspalvelurutiini kutsuu vastauksena itse keskeytykseen, mutta jota ei välttämättä suoriteta välittömästi). Tämä hankala nimi piilottaa ajurien etsintäprosessin, jonka tiedostot sisältävät tietoa, että ajuri vaatii liikaa prosessorilta huoltaakseen sille nimenomaan määrättyä laitettaan. Tässä julkaisijoiden sivu:

http://www.resplendence.com/latencymon

josta en kuitenkaan sokaisin silmin löytänyt latauslinkkiä, ja siksi annan sinulle mahdollisuuden ladata ohjelma verkkosivustoltani

LATAA OHJELMA ILMAISEKSI

Käynnistettyään se ilmoitti minulle välittömästi mahdollisista DVD-aseman ongelmista atapi.sys on vastuussa nimenomaan siitä (ja muuten, asema ei ole toiminut melkein 3 kuukauteen...). Varoittaa, että sinun on ehkä päivitettävä BIOS:

Siirry välilehdelle Kuljettajat ja lajittele ne haavoittuvimpien merkkien mukaan napsauttamalla saraketta DPC-määrä:

Katso tarkemmin rivin ensimmäisiä: he ja voi olla ongelmiesi syy.

  • KAIKKI TAPAHTUI JOTAkin YHTÄkkiä, UUDELLEENKÄYNNISTYSTEN JÄLKEEN

Oli hetki, jolloin ei onnistu Jarrujen syytä ei voitu eritellä. Tapaus auttoi: käyttäjä "tarttui" virukseen, joka tuhosi DirectX:n kokonaan, ja toimi äärimmäisen valikoivasti tappaen Windowsin järjestelmätiedostot jättäen DirectX-pelitiedostoja. Minun piti korjata järjestelmä päivityksellä, ja katso ja katso! – roskien mukana katosivat myös järjestelmäkeskeytykset. Kesti vähän aikaa, mutta tulos oli odottamaton. Syyllisiä eivät olleet virukset tai ajurit, vaan päivityspaketit. Tässä heidän nimensä:

  • KB3199986
  • KB4013418
  • KB3211320

Väitän, että JÄLKEEN JÄLKEEN NÄMÄ PÄIVITYKSET, että tietty käyttäjä alkoi kärsiä ylikuormituksesta järjestelmän keskeytyksistä. Jotain tällaista... ajattelemisen aihetta sinulle.

  • SULKEMME VIALLISET LAITTEET

Tämä voi myös olla syy siihen, miksi järjestelmäkeskeytykset ylikuormittavat prosessoria. Aloita tarkistaminen, eikö edellinen rikkinäisten ohjainten haku tuonut menestystä. Itse Windows ja sen sisäänrakennetut itsediagnoosiapuohjelmat auttavat sinua löytämään laitteistoon liittyviä ongelmia. Olen jo kirjoittanut niistä artikkelissa. Selaa läpi, tiedoista on hyötyä, siitä ei ole epäilystäkään. Muista, että liittimestä irronneet kaapelit voivat myös aiheuttaa epäonnistumisia. Itse törmäsin ongelmiin sekä prosessorin ylikuumenemisen että "unohtelun" kanssa päivittäessäni BIOS:ia upouusia Windows 10:tä varten (lisätietoja alla) - jotka kaikki johtivat havaittaviin järjestelmän keskeytyksiin.

HUOMAUTUS. Jos järjestelmähäiriöt vaivaavat kannettavaa tietokonettasi, sinun on varmistettava, ettei sinulla ole kuoleva akkuongelma. Lue artikkeli itse.

  • TARKISTA WINDOWS-ÄÄNIOHJELMASSI

Itse asiassa puhumme Windowsin äänitehosteiden palauttamisesta oletusarvoihin. Napsauta äänikuvaketta hiiren kakkospainikkeella ja napsauta Toistolaitteet:

Kaksoisnapsauta Toisto-välilehdessä oletuslaitteiden kohdetta (minulle Kaiuttimet), siirry välilehdelle Lisäominaisuuksia ja valitse vieressä oleva valintaruutu Poista kaikki tehosteet käytöstä. Käytä - OK. Käynnistä uudelleen ja tarkista:

  • ONKO BIOS Syyllinen?

Se on mahdollista. BIOS on ensimmäinen ohjelma, joka käynnistyy, kun painat tietokoneen virtapainiketta. Joten on aika tarkistaa BIOS-päivitykset. Ja jotta oikean version etsiminen ei kestä, tarkista BIOS-versiosi heti. komentokonsolissa cmd kirjoita kaksi komentoa peräkkäin:

Järjestelmätiedot | findstr /I /c:bios wmic bios get valmistaja, smbiosbiosversion

minä ensimmäisessä joukkueessa - tämä on iso latina i.

Onko se kovalevy?

“Aika ja jopa erittäin hyvä.” Helpoin tapa on tarkistaa levy virheiden varalta käyttämällä sisäänrakennettuja työkaluja, kuten chkdsk. Jos järjestelmän keskeytykset ovat laantuneet "ajon" jälkeen, syy on löydetty. Kuitenkin, jos ongelma ilmenee yhä uudelleen, kaikesta tästä huolimatta chkdsk havaitsee poikkeuksetta virheet, sinulla on ongelmia (kiintolevyn, virtalähteen tai emolevyn kanssa) - varaudu pahimpaan.

P.S. No, arvostelujen perusteella ihmiset ovat vaivautuneita ongelmasta. Lupaan kehittää aihetta tulevissa artikkeleissa.

Toivon sinulle menestystä.

Luettu: 1,238

Keskeytyspyyntöjen yhteydessä suoritettavien rutiinien tärkeä ominaisuus on, että ne suorittavat työtä, jolla ei useimmiten ole mitään tekemistä nykyisen prosessin kanssa.

Levyohjain voi esimerkiksi saada ohjauksen sen jälkeen, kun levyohjain on kirjoittanut prosessilta A vastaanotetun tiedon asianmukaisiin sektoreihin, mutta tämä ajankohta ei ole sama kuin prosessin A tai sen säikeen seuraavan iteraation jakso.

Tyypillisimmässä tapauksessa prosessi A odottaa I/O-toiminnon valmistumista (jos toiminto on käynnissä synkronisesti) ja levyohjain keskeyttää jonkin muun prosessin.

Joissakin tapauksissa on yleensä vaikea määrittää yksiselitteisesti, mille prosessille tietty käyttöjärjestelmän ohjelmistomoduuli, esimerkiksi säikeen ajoitus, suorittaa työtä. Siksi tällaiselle menettelylle asetetaan rajoituksia - heillä ei ole oikeutta käyttää resursseja (muisti, avoimet tiedostot jne.), joiden kanssa nykyinen prosessi toimii.

Keskeytysrutiinit toimivat niiden resurssien kanssa, jotka niille oli varattu, kun vastaava ajuri alustettiin tai itse käyttöjärjestelmä alustettiin. Nämä resurssit kuuluvat käyttöjärjestelmälle, eivät tietylle prosessille. Näin muisti varataan ajureille järjestelmäalueelta. Siksi on yleistä sanoa, että keskeytysrutiinit toimivat prosessin kontekstin ulkopuolella.

Keskeytysten välitys on tärkeä käyttöjärjestelmän ominaisuus, ja tämä ominaisuus on toteutettu lähes kaikissa moniohjelmointikäyttöjärjestelmissä. Pääsääntöisesti käyttöjärjestelmä toteuttaa kaksitasoisen työn ajoitusmekanismin. Ajoituksen ylimmän tason suorittaa keskeytyshallinta, joka jakaa prosessoriajan erityyppisten - ulkoisten, sisäisten ja ohjelmistojen - keskeytyksiä koskevien saapuvien pyyntöjen virran kesken. Jäljellä olevan prosessoriajan varaa toinen lähettäjä - säikeen välittäjä, joka perustuu kvantisointimenetelmiin ja muihin, joita olemme tarkastelleet.

Järjestelmäpuhelut

Järjestelmäkutsun avulla sovellus voi ottaa yhteyttä käyttöjärjestelmään ja pyytää tietyn toiminnon suorittamista, joka on muotoiltu käyttöjärjestelmän koodisegmentin proseduuriksi (tai toimintosarjaksi).

Sovellusohjelmoijalle käyttöjärjestelmä näyttää kirjastolta, joka toteuttaa hyödyllisiä toimintoja, jotka helpottavat sovellustehtävän hallintaa tai käyttäjätilassa kiellettyjen toimien suorittamista, esimerkiksi tietojen vaihtamista I/O-laitteen kanssa.

Järjestelmäkutsujen toteutuksen on täytettävä seuraavat vaatimukset:

· tarjota vaihto etuoikeutettuun tilaan;

· on nopea kutsua OS menettelyjä;

· tarjota yhtenäinen pääsy järjestelmäkutsuihin kaikille laitteistoalustoille, joilla käyttöjärjestelmä toimii;

· mahdollistaa järjestelmäkutsujen joukon helpon laajentamisen;

· antaa käyttöjärjestelmän hallinnan järjestelmäkutsujen oikeaan käyttöön

Useimmissa käyttöjärjestelmissä järjestelmäpuhelut käsitellään keskitetysti järjestelmäpuhelunhallinnan olemassaolon perusteella.

Jokaiselle järjestelmäkutsulle sovellus suorittaa ohjelmistokeskeytyksen tietyllä ja ainutlaatuisella vektorinumerolla.

Ennen ohjelmistokeskeytyksen suorittamista sovellus välittää järjestelmäkutsunumeron käyttöjärjestelmälle. Lähetystapa riippuu toteutuksesta. Numero voidaan esimerkiksi sijoittaa tiettyyn prosessorirekisteriin tai kuljettaa pinon läpi. Myös järjestelmäkutsuargumentit välitetään jollain tavalla, ne voidaan siirtää joko yleiskäyttöisiin rekistereihin tai RAM-pinon tai -ryhmän kautta.

Menettelyosoite 21h
Menettelyosoite 22h
Menettelyosoite 23h
Järjestelmän puhelunjohtajan osoite
Järjestelmäpuhelunhallinta
Menettely järjestelmäkutsujen käsittelyyn 21h
Käsittelymenettely Järjestelmäpuhelu 22h
Käsittelymenettely Järjestelmäpuhelu 23h

Kun järjestelmäpuhelu on valmis, ohjaus palautetaan lähettäjälle, ja hän saa myös tämän puhelun lopetuskoodin. Välittäjä palauttaa prosessorin rekisterit, asettaa paluukoodin tiettyyn rekisteriin ja suorittaa keskeytyksestä palautuskäskyn, joka palauttaa prosessorin etuoikeutettoman tilan.

Kuvattu taulukkomuotoinen menetelmä järjestelmäkutsujen järjestämiseksi hyväksytään melkein kaikissa käyttöjärjestelmissä. Sen avulla voit helposti muokata järjestelmäpuhelujen koostumusta lisäämällä taulukkoon uuden osoitteen ja laajentamalla kelvollisten puhelunumeroiden valikoimaa.

Käyttöjärjestelmä voi suorittaa järjestelmäkutsuja synkroninen tai asynkroninen tilat.

Synkroninen järjestelmäpuhelu tarkoittaa, että tällaisen puhelun tehnyt prosessi keskeytetään, kunnes järjestelmäkutsu on suorittanut kaikki vaaditut työt . Tämän jälkeen ajastin asettaa prosessin valmiustilaan.

Asynkroninen järjestelmäpuhelu ei aiheuta prosessin siirtymistä lepotilaan, joidenkin järjestelmän alkutoimintojen, kuten I/O-toiminnon aloittamisen, jälkeen ohjaus palaa sovellusprosessiin.

Useimmat käyttöjärjestelmän järjestelmäkutsut ovat synkronisia.

Kun ydintilan koodi, jolla on korkein prioriteetti, on käynnissä, mikään muu koodi ei voi toimia kyseisessä prosessorissa. Tietenkin, jos liian paljon koodia suoritetaan liian korkeilla IRQL-arvoilla, tämä johtaa väistämättä järjestelmän yleiseen heikkenemiseen.

Tämän tyyppisen ongelman ratkaisemiseksi ydintilassa ajettava koodi on suunniteltava siten, että se ei toimi kohonneella IRQL-tasolla pitkiä aikoja. Yksi tämän strategian tärkeimmistä osista on Deferred Procedure Calls (DPC) - lykätyt menettelypuhelut.

DPC:n toiminta

Viivästettävien prosessikutsujen käyttömalli antaa sinun rakentaa suoritusprosessin siten, että tehtävä voidaan suorittaa suunniteltu koodi toimii korkealla IRQL-tasolla, mutta se ei ole vielä toiminut suoritettu . Tämä suorituksen lykkäys on hyödyllinen, kun keskeytystä huolletaan ohjaimessa, eikä ole mitään syytä estää muun koodin suorittamista alemmalla IRQL-tasolla. Toisin sanoen, kun tietyn tilanteen käsittely voidaan kivuttomasti siirtää myöhempään ajankohtaan.

DPC-toimintojen kutsumispyyntöjen tallentamiseksi käyttöjärjestelmä ylläpitää DPC-objektien jonoa.

Aluksi rajoittumme tarkastelemaan yksinkertaisempaa tapausta työskennellä DPC-menettelyjen kanssa, jotka on tarkoitettu käytettäväksi keskeytyskäsittelyn yhteydessä. Tämän tyyppiset DPC-menettelyt saivat kirjallisuudessa erityisnimen DpcForIsr.

Keskeytysrutiineissa käytettävä DPC-objekti luodaan kutsumalla IoInitializeDpcRequest, suoritetaan yleensä ohjaimen käynnistystoimenpiteissä. Tämä kutsu rekisteröi DpcForIsr-ohjaimen tarjoaman menettelyn ja liittää sen luotavaan objektiin - melko yleinen tekniikka Windowsissa. Erityisesti on huomattava, että tämän kutsun luoma DPC-objekti jää käyttöjärjestelmän syvyyksiin, ohjaimen kehittäjän ulottumattomiin. (DpcForIsr:n ja muiden DPC-menettelyjen välinen ero on vain siinä, että jälkimmäisiä käytetään kutsujen avulla Ke...Dpc, ja niille luodut DPC-objektit ovat ohjaimen kehittäjän käytettävissä.)

Jos kuljettaja on rekisteröinyt DpcForIsr-proseduurinsa, silloin kun ISR-keskeytystä proseduuri käsittelee, vastaava DPC-objekti voidaan sijoittaa järjestelmän DPC-jonoon (itse asiassa pyyntö kutsua tämä DpcForIsr-proseduuri myöhemmin) - kutsun avulla IoRequestDpc. DpcForIsr-menettely suorittaa myöhemmin vastaanotetun ISR:n käsittelyn pyyntömenettelyllä, joka suoritetaan vähemmän kriittisissä olosuhteissa ja alhaisella IRQL-tasolla.

Yleisesti ottaen DPC-menettelyjen (tässä tapauksessa DpcForIsr) toiminta koostuu seuraavista toiminnoista:

  • Kun korkealla (laitteistolla) olevalla IRQL:llä toimiva koodinpätkä haluaa ajoittaa osan työstään tehtäväksi alhaisella IRQL:llä, se lisää DPC-objektin järjestelmän viivästettyyn prosessikutsujonoon.
  • Ennemmin tai myöhemmin prosessorin IRQL-arvo putoaa alle DISPATCH_LEVEL, ja keskeytyksen viivästynyttä työtä palvelee DPC-toiminto. DPC-hallinta noutaa jokaisen DPC-objektin jonosta ja kutsuu vastaavan funktion, jonka osoitin on tallennettu kyseiseen objektiin. Tätä toimintoa kutsutaan, kun prosessori on käynnissä tasolla DISPATCH_LEVEL.

DPC-mekanismin ominaisuudet

Yleensä lykättyjen toimintokutsujen käyttäminen ei ole vaikeaa, koska Windows 2000/XP/Server 2003 -käyttöjärjestelmät tarjoavat suuren joukon järjestelmäkutsuja, jotka piilottavat suurimman osan tämän prosessin yksityiskohdista. Kaksi DPC:n kanssa työskentelyn petollisinta näkökohtaa on kuitenkin korostettava.

Ensinnäkin Windows NT 5 asettaa rajoituksen, jonka mukaan yksi DPC-objektin esiintymä voidaan sijoittaa järjestelmän DPC-jonoon tiettynä aikana. Yritykset laittaa DPC-jonoon objekti, joka täsmälleen vastaa olemassa olevaa objektia, hylätään. Tämän seurauksena vain yksi DPC-menettelykutsu tapahtuu, vaikka kuljettaja odottaisikin kahden puhelun soittamista. Tämä voi tapahtua, jos huolletun laitteen aiheuttamia keskeytyksiä on kaksi ja ensimmäisen viivästetyn proseduurikutsun käsittely ei ole vielä alkanut. DPC-objektin ensimmäinen esiintymä on edelleen jonossa, kun taas ohjain on jo aloittanut toisen keskeytyksen käsittelyn.

Ohjaimen suunnittelussa on oltava sellainen DPC-mekanismin toimintatapa. Ehkä ylimääräinen DPC-pyyntölaskuri pitäisi tarjota, tai ohjain voisi toteuttaa oman pyyntöjononsa. Kun varsinainen viivästetty toimenpide suoritetaan, voit tarkistaa laskurin ja sen oman pyyntöjonon määrittääksesi, mitä tiettyä työtä tulisi tehdä.

Toiseksi, on olemassa merkittäviä synkronointiongelmia käytettäessä moniprosessorialustoja. Oletetaan, että yhdellä prosessorilla toimiva koodi suorittaa keskeytyspalvelun ja ajoittaa DPC-proseduurikutsun (asettaa DPC-objektin järjestelmäjonoon). Kuitenkin ennen kuin keskeytys on täysin käsitelty, toinen prosessori voi aloittaa DPC:n käsittelyn järjestelmäjonoon asetetun objektin. Tällöin syntyy tilanne, jossa keskeytyspalvelukoodi suoritetaan rinnakkain ja samanaikaisesti DPC-proseduurikoodin kanssa. Tästä syystä on tarpeen toteuttaa toimenpiteitä, joilla synkronoidaan luotettavasti DPC-proseduuriohjelmakoodin pääsy ajurin keskeytyspalvelurutiinin kanssa jaettuihin resursseihin.

Jos katsot tarkemmin puheluparametrien luetteloa IoInitializeDpcRequest Ja IoRequestDpc(tarkoitettu toimimaan DpcForIsr-proseduurien kanssa), on helppo huomata, että DPC-objekti on "sidottu" laiteobjektiin. Kun tämä objekti asetetaan DPC-jonoon ISR-proseduurin ollessa käynnissä, myös laiteobjekti määritetään. Tämä varmistaa varmuuden siitä, mikä tietty DPC-proseduurikutsu on "järjestetty" ISR-proseduurilla (korrelaatio laiteobjektin mukaan). Tämä tarkoittaa myös sitä, että ajuri, joka on luonut useita laiteobjekteja (melko harvinainen tapaus), voi käyttää myös useita DpcForIsr-proseduureja - yhtä jokaiselle laiteobjektille.

Järjestelmän DPC-mekanismi estää DPC-objektien samanaikaisen käsittelyn järjestelmäjonosta, jopa moniprosessorikokoonpanossa. Näin ollen, jos resurssit jaetaan useiden viivästettyjen toimenpiteiden kesken, ei tarvitse huolehtia pääsyn synkronoinnista niihin.

Yllä keskustelimme DPC-menettelyjen käytöstä keskeytyskäsittelyn, toisin sanoen DpcForIsr:n, suorittamiseen. DPC-menettelyjä voidaan kuitenkin käyttää muillakin tavoilla, esimerkiksi ajastimien yhteydessä odottamisen järjestämiseen. Voit tehdä tämän luomalla DPC-objektin soittamalla KeInitializeDPC, joka yhdistää tämän objektin ohjaimen sisältämään DPC-proseduuriin. Voit sitten asettaa aikakatkaisun esialustettuun (käyttäen KeInitializeTimer tai KeInitializeEx) ajastinobjekti. Puhelua käytetään odotusajan asettamiseen KeSetTimer, joka on välitettävä osoitin alustettuun DPC-objektiin yhtenä parametristaan. Kun DPC-aikakatkaisu umpeutuu, objekti lisätään järjestelmän DPC-jonoon ja siihen liittyvä DPC-proseduuri kutsutaan mahdollisimman pian. Tämän toisen tyypin DPC-menettelyt on merkitty DDK-dokumentaatiossa termillä "Mukautettu DPC". (Tämä DPC-menettelyjen käyttö tekee niistä hyvin samanlaisia ​​käyttäjätilan APC-kutsuja.)

Jos haluat sijoittaa toisen tyyppisiä DPC-proseduureja (ei liity keskeytuksiin) vastaavat objektit järjestelmän DPC-jonoon, käytä kutsua KeInsertQueueDpc. Vastaavasti puhelun aloituskoodin tulee toimia IRQL-tasolla, joka ei ole alempi kuin DISPATCH_LEVEL.

Jos haluat tyhjentää järjestelmän DPC-jonon mukautetuista DPC-proseduureista, esimerkiksi jos ohjaimen on pikaisesti sammutettava, soita KeRemoveQueueDpc, jota voidaan kutsua koodista millä tahansa IRQL-tasolla.

Lähetä hyvä työsi tietokanta on yksinkertainen. Käytä alla olevaa lomaketta

Opiskelijat, jatko-opiskelijat, nuoret tutkijat, jotka käyttävät tietopohjaa opinnoissaan ja työssään, ovat sinulle erittäin kiitollisia.

LASKENTA JA SELITTÄVÄ HUOMAUTUS

kurssiprojektiin aiheesta:

Sovellusprofiili

1. Esittely

2. Analyyttinen osa

2.1. Tekninen tehtävä

2.2. Windows NT 5.x -arkkitehtuurin yleiskatsaus

2.3. Kuljettajan luokitus

2.4. Legacy-ohjaimen yleinen rakenne

2.4.1. DriverEntry menettely

2.4.2. DriverUnload-menettely

2.4.3. Työnkulut IRP-pakettien käsittelyyn

2.4.3.1. IRP-paketin otsikko

2.4.3.2. IRP-pino

2.4.3.3. Paketinkäsittelytoiminto IRP_MJ_CREATE

2.4.3.4. Paketinkäsittelytoiminto IRP_MJ_CLOSE

2.4.3.5. Paketinkäsittelytoiminto IRP_MJ_DEVICE_CONTROL

2.4.4. ISR - Keskeytä palvelurutiini

2.4.5. DPC - viivästetty puhelumenettely

3. Suunnitteluosa

3.1. Vanha kuljettaja

3.1.1. DriverEntry menettely

3.1.2. DriverUnload

3.1.3. DispatchCreate ja DispatchClose

3.1.4. DispatchDeviceControl

3.2. Mukautettu sovellus

4. Tekninen osa

4.1. Käyttöjärjestelmän ja ohjelmointiympäristön valinta.

4.2. Käyttöliittymä

4.3. Laitteistovaatimukset

5. Päätelmät.

6. Luettelo käytetystä kirjallisuudesta.

1. Johdanto

Hyvin usein ohjelmistoa kehitettäessä on tarpeen tarkkailla sen toimintaa: kuinka kauan sen säikeet ovat käynnissä ydintilassa, kuinka kauan käyttäjätilassa, kuinka kauan he viettävät aikaa odottamiseen sekä kontekstin vaihtojen lukumäärää yhdestä tilasta toiselle. Kaikki tämä on tärkeää, koska jokaisella tilalla on omat ominaisuutensa. Ydintilassa koodi toimii nopeammin, mutta data/järjestelmäkoodi voi vioittua. Toisin kuin ydintila, käyttäjätila on rajoitettu sen tarjoamissa palveluissa, jotta sen koodi ei voi kaataa järjestelmää. Samaa tarkoitusta varten käyttäjätilassa tehdään lisätarkastuksia haitallisten ohjeiden suorittamisen estämiseksi. Siksi käyttäjämoodin koodin suoritusnopeus on huomattavasti pienempi. Kontekstikytkimien määrä vaikuttaa myös koodin suoritusnopeuteen, koska tämä operaatio on melko kallis (noin 2000 kellojaksoa). Tämä oli selvästi havaittavissa laboratoriotyön ja tietokonegrafiikan kurssiprojektin kehitystyön aikana: piirrettäessä kuva pikseli kerrallaan SetPixel-toiminnolla piirtonopeus oli suhteettoman hitaampi kuin käytettäessä käyttäjätilapuskuria, johon tieto väristä puskurielementtejä vastaavista pikseleistä syötettiin asteittain. Tämä johtui siitä, että SetPixel-toimintoa käytettäessä tapahtui kaksi kontekstin vaihtoa (käyttäjätilasta ydintilaan ja takaisin) pikseliä kohden, ja käytettäessä puskuria, joka tallentaa kontekstista riippumattoman väriesityksen, tapahtui samat kaksi kytkintä, mutta kerran koko kehyksen piirtämiseen.

Siten kyky saada selville yllä olevat tilastotiedot kohdeohjelmistosta mahdollistaa ohjelman niin sanottujen pullonkaulojen nopean havaitsemisen, jotka estävät koko sovelluksen suorituskyvyn parantamisen.

2. Analyyttinen osa

2.1 Tekninen tehtävä

Esitettävän kurssiprojektin tavoitteena on kehittää yksinkertainen sovellusprofiloija, joka sisältää:

Vanha ohjain, jonka pitäisi:

Päivitä säännöllisesti tietoja prosesseista ja niiden virroista;

Tarjoa perustiedot prosesseista ja niiden säikeistä;

Anna valitulle säikeelle laitteistokonteksti;

Varmista suojattu pääsy näihin tietoihin useiden käyttäjien asiakassovelluksista.

Mukautettu sovellus, jonka avulla voit:

Asenna ja poista ohjain oikein ilman tarvetta käynnistää järjestelmä uudelleen;

Ota yhteyttä kuljettajaan erilaisten tietojen saamiseksi.

2.2 Arkkitehtuurin yleiskatsausWindows NT 5.x

Windowsissa sovellukset ovat erillisiä itse käyttöjärjestelmästä. Sen ydinkoodi toimii etuoikeutetussa prosessoritilassa ( ytimen tila), joka tarjoaa pääsyn järjestelmätietoihin ja laitteistoihin. Sovelluskoodi toimii etuoikeutettoman prosessoritilassa ( mukautettu tila) joilla on epätäydellinen rajapinta, rajoitettu pääsy järjestelmätietoihin eikä suoraa pääsyä laitteisiin. Kun käyttäjätilan ohjelma kutsuu järjestelmäpalvelua, prosessori sieppaa puhelun ja vaihtaa kutsuvan säikeen ydintilaan. Kun järjestelmäpalvelu päättyy, käyttöjärjestelmä vaihtaa säikeen kontekstin takaisin käyttäjätilaan ja jatkaa sen suorittamista.

Seuraavassa on kaavamaisesti esitetty Windows-arkkitehtuurin osa, johon tämä kurssiprojekti vaikuttaa. Komponentteja, kuten järjestelmätukiprosesseja, palveluprosesseja, ympäristön alijärjestelmiä, laitteiston abstraktiotasoa sekä ikkunoiden ja grafiikan tukea, ei määritellä tässä.

Käyttäjäsovellukset ovat eräänlainen käyttäjäprosessi, joka toimii käyttäjätilassa, jossa ne rajoittuvat käyttämään etuoikeutettomia ohjeita.

Alijärjestelmän DLL:t – Windowsissa käyttäjäsovellukset eivät voi kutsua käyttöjärjestelmäpalveluita suoraan, vaan ne toimivat yhden tai useamman alijärjestelmän DLL:n kanssa, joiden tarkoituksena on muuntaa dokumentoidut toiminnot vastaaviksi sisäisiksi (ja yleensä dokumentoimattomiksi) kutsuiksi järjestelmäpalveluihin.

Toimeenpanojärjestelmä sisältää käyttöjärjestelmän ydinpalvelut, jotka tarjoavat muistin, prosessien ja säikeiden hallinnan, suojauksen, I/O:n ja prosessien välisen viestinnän.

Ydin sisältää matalan tason käyttöjärjestelmän toimintoja, jotka tukevat esimerkiksi säikeen ajoitusta, keskeytystä ja poikkeusten lähettämistä. Se tarjoaa myös joukon proseduureja ja perusobjekteja, joita toimeenpanojärjestelmä käyttää korkeamman tason rakenteiden toteuttamiseen.

Ohjaimia käytetään laajentamaan ytimen toimintoja.

2.3 Kuljettajan luokitus

Toisin kuin käyttäjäsovellus, ohjain ei ole prosessi eikä sillä ole suoritussäiettä. Sen sijaan ohjaus siirtyy kuljettajalle käyttäjäsovelluksen tai ajurin I/O-pyynnön tai keskeytyksen seurauksena. Ensimmäisessä tapauksessa ohjaimen suorituskonteksti tunnetaan tarkasti - se on sovellusohjelma. Toisessa tapauksessa suorituskonteksti voi olla joko tunnettu tai satunnainen - se riippuu kutsuvan ajurifunktion suorituskontekstista. Kolmannessa tapauksessa suorituskonteksti on satunnainen, koska keskeytys (ja vastaavasti ajurikoodin suoritus) voi tapahtua minkä tahansa sovellusohjelman suorituksen aikana.

Sijainnin mukaan ohjainpinossa:

Korkeamman tason ajurit – vastaanottavat pyyntöjä käyttäjäsovelluksesta ja ovat vuorovaikutuksessa alemman tason ohjaimien kanssa;

Keskitason ajurit – vastaanottavat pyyntöjä ylävirran ajureilta ja ovat vuorovaikutuksessa alavirran ajureiden kanssa;

Matalan tason ajurit vastaanottavat pyyntöjä korkeamman tason ajureilta ja suorittavat pyyntöpakettien lopullisen käsittelyn.

Korosta myös konseptia monoliittinen kuljettaja- huipputason ajuri, joka ei ole vuorovaikutuksessa muiden ohjainten kanssa.

Windows-ohjainmallin (WDM - Windows Driver Model) parantamisen yhteydessä, johon lisättiin Plug and Play -tuki ja energiansäästöteknologiat, ajurit alettiin jakaa:

Vanhat ajurit (Vanhat ajurit, NT-tyyliset ajurit) - vanhaan tyyliin kirjoitetut ajurit ilman innovaatioiden tukea;

WDM-ajurit - ajurit, jotka täyttävät kaikki laajennetun WDM-mallin vaatimukset.

2.4 Legacy-ohjaimen yleinen rakenne

Legacy-ohjaimella on seuraavat päätulokohdat:

DriverEntry - kuljettajan latausmenettely;

DriverUnload - kuljettajan purkumenettely;

Toimintamenettelyt IRP-pakettien käsittelyyn;

ISR-menettely (Interrupt Service Routine) - keskeytysproseduuri;

DPC-menettely (Deferred Procedure Call) - viivästetty puhelumenettely.

2.4.1 DriverEntry menettely

Tämä menettely on olemassa kaikissa ajureissa, ja I/O-hallinta kutsuu sitä, kun ajuri ladataan.

Vanhat ajurit tekevät siinä huomattavasti enemmän työtä kuin WDM-ajurit, koska ne pakotetaan suorittamaan AddDevice-toiminto, joka on pakollinen WDM-ajureille. Alustustehtävien ratkaisemisen ja sisääntulopisteiden rekisteröimisen lisäksi tuettujen IRP-pakettien käsittelyyn ja ajurien purkamistoimenpiteisiin täällä:

Laitteisto, jota kuljettaja hallitsee, määritetään;

Laiteobjektit luodaan (IoCreateDevice-toiminto) jokaiselle tämän ohjaimen ohjaamalle fyysiselle tai loogiselle laitteelle;

Laitteille, joiden pitäisi olla käyttäjän sovellusten näkyvissä, luodaan symbolisia linkkejä (IoCreateSymbolicLink-toiminto);

Tarvittaessa laite liitetään keskeytysobjektiin. Jos ISR-menettely edellyttää DPC-proseduurin käyttöä, vastaava objekti luodaan ja alustetaan tässä vaiheessa;

Varataan kuljettajan toimintaan tarvittava muisti.

2.4.2 DriverUnload-menettely

I/O-manageri kutsuu tätä menettelyä, kun se dynaamisesti purkaa ajurin. Tämä menettely toimii päinvastoin kuin DriverEntry-menettelyssä.

Seuraavat vaiheet ovat tyypillisiä vanhoille ohjaimille:

Joillekin laitteistotyypeille on tarpeen tallentaa tila järjestelmän rekisteriin, koska näitä tietoja voidaan käyttää ajuria myöhemmin ladattaessa;

Jos keskeytykset ovat käytössä huollettavalle laitteelle, purkutoimenpiteen on poistettava ne käytöstä ja irrotettava keskeytysobjektista. Tilanne, jossa laite tuottaa keskeytyksiä olemattomalle keskeytysobjektille, johtaa väistämättä järjestelmän kaatumiseen;

Poista laiteobjekti (IoDeleteDevice);

Kuljettajalle varatun muistin vapauttaminen käytön aikana.

2.4.3 Työnkulut IRP-pakettien käsittelyyn

I/O Manager kutsuu kaikkia toimintoja, jotka on rekisteröity DriverEntry-menettelyyn täyttämällä MajorFunction-taulukko, käsittelemään asianmukaisia ​​pyyntöjä ohjaimen asiakkailta. Nämä pyynnöt muotoillaan aina erityisten tietorakenteiden - IRP-pakettien - muodossa, joille I/O Manager varaa muistia sivuttamattomassa järjestelmäpoolissa. IRP-paketin rakenne on sellainen, että se koostuu kiinteän kokoisesta otsikosta ja IRP-pinosta, jonka koko riippuu pinossa olevien laiteobjektien määrästä.

2.4.3.1 IRP-paketin otsikko. IRP-paketin otsikkorakenteessa on seuraavat kentät:

IoStatus-kenttä, jonka tyyppi on IO_STATUS_BLOCK, sisältää kaksi alikenttää:

Status sisältää arvon, jonka ajuri asettaa paketin käsittelyn jälkeen;

Tieto sisältää useimmiten lähetettyjen tai vastaanotettujen tavujen määrän.

PVOID-tyyppinen AssociatedIrp.SystemBuffer-kenttä sisältää osoittimen järjestelmäpuskuriin siltä varalta, että laite tukee puskuroitua I/O:ta;

PMDL-tyypin MdlAddress-kenttä sisältää osoittimen MDL-luetteloon, jos laite tukee suoraa syöttöä/tulostusta;

UserBuffer-kenttä, jonka tyyppi on PVOID, sisältää I/O:n käyttäjäpuskurin osoitteen;

Peruuta BOOLEAN-kenttä osoittaa, että IRP on peruutettava.

2.4.3.2 IRP-pakettipino. IRP-pinosolujen ensisijainen tarkoitus on tallentaa toimintokoodia ja I/O-pyyntöparametreja. Alimman tason ohjaimelle osoitetulle pyynnölle vastaavalla IRP-paketilla on vain yksi pinopaikka. Ylemmän tason ohjaimelle lähetettävälle pyynnölle I/O Manager luo IRP:n, jossa on useita pinosoluja, yksi jokaiselle laiteobjektille.

Jokainen IRP-pinosolu sisältää:

UCHAR-tyyppinen MajorFunction on koodi, joka kuvaa toiminnon tarkoitusta;

UCHAR-tyyppinen MinorFunction on koodi, joka kuvaa toiminnon alikoodia;

DeviceObject, jonka tyyppi on PDEVICE_OBJECT, on osoitin laiteobjektiin, jolle tämä IRP-pyyntö osoitettiin;

FileObject tyyppiä PFILE_OBJECT - tämän pyynnön tiedostoobjekti;

Liitostyypin parametrit - sovellus riippuu MajorFunction-arvosta.

I/O-manageri käyttää MajorFunction-kenttää hakeakseen pyynnön käsittelemiseen tarvittavan proseduurin MajorFunction-taulukosta.

Jokaisen IRP-pakettien käsittelymenettelyn on oltava parametreja:

Osoitin laiteobjektiin, jolle IRP-pyyntö on tarkoitettu;

Osoitin IRP:lle, joka kuvaa tätä pyyntöä;

2.4.3.3 Paketinkäsittelytoiminto IRP_MJ_CREATE. Tämä toiminto on suunniteltu käsittelemään ajurikuvauspyyntöjä käyttäjäsovelluksista tai ajureista. Tyypillisesti tämä toiminto yksinkertaisesti merkitsee IRP-paketin valmiiksi.

2.4.3.4 Paketinkäsittelytoiminto IRP_MJ_CLOSE. Tämä toiminto on suunniteltu käsittelemään ajurin kahvan sulkemispyyntöjä käyttäjäsovelluksista tai ajureista. Tyypillisesti tämä toiminto yksinkertaisesti merkitsee IRP-paketin valmiiksi.

2.4.3.5 Paketinkäsittelytoiminto IRP_MJ_DEVICE_CONTROL. Tämän toiminnon avulla voit käsitellä edistyneitä pyyntöjä käyttäjätilan asiakkailta, joita käytetään useimmiten tietojen vaihtamiseen sovelluksen ja ohjaimen välillä. Tällainen pyyntö voidaan generoida kutsumalla DeviceIoControl-toiminto käyttäjätilasta.

Se käyttää IOCTL-koodeja (I/O-ohjauskoodi), joista osa on käyttöjärjestelmän ennalta määrittelemiä ja joista osan voi luoda ohjaimen kehittäjä. Tämän koodin määrittää I/O Managerin pyyntö IRP-pakettia luodessaan.

Ohjaintoiminnot, jotka toimivat IOCTL-pyyntöjen perusteella, vaativat usein puskurialueen määrittämisen tulo- tai lähtötietojen vastaanottamiseksi. Tilanne on mahdollinen, kun molempia puskureita käytetään yhdessä pyynnössä.

I/O Managerin tarjoama tietojen käyttötapa määritellään IOCTL-koodissa. Tällaisia ​​menetelmiä voivat olla:

METHOD_BUFFERED: Syöttökäyttäjäpuskuri kopioidaan järjestelmäpuskuriin, ja kun käsittely on valmis, järjestelmäpuskuri kopioidaan lähtökäyttäjäpuskuriin.

METHOD_IN_DIRECT: Tarvittavat käyttäjän puskurisivut ladataan levyltä RAM-muistiin ja lukitaan. Seuraavaksi DMA:n avulla dataa siirretään laitteen ja käyttäjän välillä.

METHOD_OUT_DIRECT: Tarvittavat käyttäjän puskurisivut ladataan levyltä RAM-muistiin ja lukitaan. Seuraavaksi DMA:n avulla dataa siirretään laitteen ja käyttäjän välillä.

METHOD_NEITHER: Tämä siirtomenetelmä ei tarkista muistin saatavuutta, varaa välipuskureita tai luo MDL:itä. IRP-paketti kuljettaa I/O-pyynnön aloittajan osoiteavaruudessa olevien puskurien virtuaaliosoitteet.

Tässä tapauksessa laiteobjektin puskuroinnin tyypin määrittävillä lipuilla ei ole merkitystä IOCTL-pyyntöjen kanssa työskennellessä. Puskuroitu vaihtomekanismi määritellään joka kerta, kun IOCTL-arvo määritetään tämän tietorakenteen omistetussa osassa. Tämä lähestymistapa tarjoaa maksimaalisen joustavuuden työskenneltäessä DeviceIoControl-käyttäjätilan kutsun kanssa.

Kuljettajan näkökulmasta dataa sisältäville tai niille tarkoitetuille puskurialueille päästään käyttämällä seuraavia rakennekenttiä:

METHOD_IN_DIRECT tai METHOD_OUT_DIRECT

Puskuroi tiedoilla

Puskurin osoite järjestelmän osoiteavaruudessa määritetään kohdassa pIrp->AssociatedIrp.SystemBuffer

Asiakkaan virtuaalinen osoite Parametreissa. DeviceIoControl. Tyyppi3 InputBuffer

Pituus määritetään kohdassa Parameters.DeviceIoControl.InputBufferLength

Puskuri datalle

Käyttää puskurointia (järjestelmäpuskuria)

Järjestelmän osoiteavaruuden puskurin osoite määritetään kohdassa pIrp->AssociatedIrp. SystemBuffer

Käyttää suoraa pääsyä, asiakaspuskuri muunnetaan MDL-listaksi, jonka osoitin sijaitsee kohdassa pIrp->MdlAddress

Asiakkaan virtuaalinen osoite kohdassa pIrp->UserBuffer

Pituus määritetään kohdassa Parameters.DeviceIoControl.OutputBufferLength

2.4.4 ISR - Keskeytä palvelurutiini

Kuljettaja rekisteröi tämän toiminnon niin, että se saa ohjauksen sillä hetkellä, kun kuljettajan palvelema laitteisto lähettää keskeytyssignaalin. Tämän toiminnon tarkoituksena on tehdä mahdollisimman vähän työtä ja rekisteröidä viivästetty puhelumenettely (DPC) keskeytyksen palvelemiseksi. Ytimen keskeytyksen hallintakutsu voi tapahtua missä tahansa kontekstissa: sekä ytimessä että käyttäjäprosessissa.

2.4.5 DPC - viivästetty puhelumenettely

Tällaiset rutiinit toimivat alemmalla keskeytyspyyntötasolla (IRQL) kuin ISR, joten ne eivät estä muita keskeytyksiä. He voivat suorittaa kaikki tai keskeyttää ISR:ssä aloitetut huoltotyöt.

3. Suunnittelu osio

Käyttäjäsovelluksen ja ohjaimen välinen vuorovaikutus järjestelmäkomponenttien kautta näyttää tältä:

3.1 Perintö-kuljettaja

Tämän kurssiprojektin Legacy driver toteuttaa seuraavat menettelyt:

DispatchCreate (käsittelee IRP_MJ_CREATE-pakettia);

DispatchClose (käsitellään IRP_MJ_CLOSE-pakettia);

DispatchDeviceControl (käsittelee IRP_MJ_DEVICE_CONTROL-pakettia).

3.1.1 DriverEntry menettely

Täällä suoritetaan tyypilliset toiminnot ajurin alustamiseksi.

Kuljettajien sisääntulopisteet on rekisteröity:

pDriverObject->DriverUnload = SpectatorDriverUnload;

PDRIVER_DISPATCH * majorFunction = pDriverObject->MajorFunction;

majorFunction[ IRP_MJ_CREATE ] = SpectatorDispatchCreate;

majorFunction[ IRP_MJ_CLOSE ] = Spectator DispatchClose;

majorFunction[ IRP_MJ_DEVICE_CONTROL ] = SpectatorDispatchDeviceControl;

Laiteobjekti nimeltä DEVICE_NAME on luotu:

#define DEVICE_NAME L"\\laite\\katselija"

RtlInitUnicodeString(&laitteennimi, DEVICE_NAME);

status = IoCreateDevice

koko (DEVICE_EXTENSION),

FILE_DEVICE_SPECTATOR,

FILE_DEVICE_SECURE_OPEN,

&pDeviceObject);

Luodulle laiteobjektille on rekisteröity symbolinen linkki SYMBOLIC_LINK:

#define SYMBOLIC_LINK L"\\DosDevices\\Spectator"

RtlInitUnicodeString(&symbolicLink, SYMBOLIC_LINK);

status = IoCreateSymbolicLink(&symbolicLink, &deviceName);

Mutex-ytimen objekti luodaan:

NTSTATUS CreateMutex()

(BEGIN_FUNC(CreateMutex);

NTSTATUS status = STATUS_SUCCESS;

status = _ExAllocatePool(g_pMutex, NonPagedPool, sizeof(KMUTEX));

jos (NT_SUCCESS(tila))

(KeInitializeMutex(g_pMutex, 0);

tila = STATUS_SUCCESS;)

END_FUNC(CreateMutex);

paluu (status);)

Tietoa prosesseista ja niiden säikeistä ladataan ensimmäistä kertaa:

jos (LockInfo() == STATUS_SUCCESS)

LockInfo()- ja UnlockInfo()-funktiot ovat yksinkertaisesti käärefunktioita LockMutex()- ja UnlockMutex()-funktioille, vastaavasti. Ensimmäinen kahdesta viimeisestä funktiosta odottaa mutex-ytimen objektia.

Ytimen objektit, joita kutsutaan mutexeiksi, takaavat, että säikeillä on toisensa poissulkeva pääsy yhteen resurssiin. Tästä tulee näiden objektien nimi (keskinäinen poissulkeminen, mutex). Ne sisältävät käyttäjälaskurin, rekursiolaskurin ja muuttujan, joka tallentaa säikeen tunnuksen. Mutexet käyttäytyvät täsmälleen samalla tavalla kuin kriittiset osat. Vaikka viimeksi mainitut ovat käyttäjätilan objekteja, mutexet ovat ydinobjekteja. Lisäksi yksi MewTex-objekti mahdollistaa useiden eri prosessien säikeiden synkronoinnin resurssiin pääsyn; Tässä tapauksessa voit asettaa enimmäisodotuksen resurssiin pääsyä varten.

Tämän mutexin ansiosta suojausvaatimus on taattu tallennettua tietoa käsiteltäessä.

Ajastimen toiminta alustetaan:

Ajastin on tarpeen tallennetun tiedon päivittämiseksi tietyin väliajoin.

Tätä varten luodaan ytimen objekti "ajastin":

status = _ExAllocatePool(g_pTimer, NonPagedPool, sizeof(KTIMER));

KeInitializeTimerEx(g_pTimer, SynchronizationTimer);

Kommentti: muisti ydinobjekteille on varattava yksinomaan sivuttamattomassa poolissa (NonPagedPool-avainsana).

Ajastimet voivat olla kahdenlaisia:

SynchronizationTimer - kun määrätty aikaväli tai ajanjakso on kulunut, se asetetaan signaalitilaan, kunnes jokin sitä odottavista säikeistä herää. Sitten ajastin kytketään ei-signaalitilaan.

NotificationTimer -- kun määritetty aikaväli tai ajanjakso on kulunut umpeen, se asetetaan signaalitilaan ja kaikki sitä odottavat säikeet herätetään. Tällainen ajastin pysyy signaloidussa tilassa, kunnes se on nimenomaisesti asetettu signaloimattomaan.

Jotta voit tehdä hyödyllisiä töitä ajastimella, sinun on rekisteröitävä OnTimer() DPC -menettely. Sitä varten sinun on luotava oma DPC-objekti, joka sijoitetaan ajoittain koko järjestelmän jonoon:

status = _ExAllocatePool(g_pTimerDpc, NonPagedPool, sizeof(KDPC));

KeInitializeDpc(g_pTimerDpc, OnTime, NULL);

Lisäksi, koska tässä ajastimessa on suoritettava käyttäjäkontekstia vaativat ajuritoiminnot, ne on poistettava OnTimer()-funktiosta, joka on DPC-toiminto, ja siksi vain järjestelmäkonteksti on käytettävissä sen aikana. teloitus. Sinun on kuitenkin varmistettava, että vaadittu työ tehdään kohtuullisessa synkronoinnissa ajan kanssa, kun DPC-funktioobjekti poistetaan käsittelyjonosta. Tätä varten luomme ketjun, joka on omistettu jonkin tapahtuman odottamiseen:

OBJECT_ATTRIBUTES objectAttributes;

InitializeObjectAttributes(&objectAttributes, NULL, OBJ_KERNEL_HANDLE,

status = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS, &objectAttributes,

NULL, NULL, UpdateThreadFunc, NULL);

KeInitializeEvent(g_pUpdateEvent, SynchronizationEvent, FALSE);

Kommentti: Tapahtumaytimen objektit ovat tyypiltään identtisiä ajastinytimen objektien kanssa.

Kun tämä tapahtuma vastaanotetaan, säie päivittää järjestelmätiedot prosesseista ja niiden säikeistä. Siirrämme tämän tapahtuman kohteen signaalitilaan OnTimer()-funktiossa. Tämä synkronointimenetelmä mahdollisti sen, että tarvittavat toiminnot suoritetaan tietyin väliajoin enintään millisekunnin tarkkuudella, kuten alla olevista viesteistä seuraa, jonka DebugView-ohjelma sieppasi ohjaimen debug-versiosta:

0,00075233 ^^^^^^^^ OnTime ^^^^^^^^

0.00116579 ======== LockInfo ========

0.00118814 ======== ReloadInfo ========

0,99727142 ^^^^^^^^ OnTime ^^^^^^^^

1.00966775 ======== LockInfo ========

1.00968981 ======== ReloadInfo ========

1,99729049 ^^^^^^^^ OnTime ^^^^^^^^

2.05610037 ======== LockInfo ========

2.05632067 ======== ReloadInfo ========

2,99727035 ^^^^^^^^ OnTime ^^^^^^^^

2.99741030 ======== LockInfo ========

2.99743295 ======== ReloadInfo ========

3,99727631 ^^^^^^^^ OnTime ^^^^^^^^

3.99739385 ======== LockInfo ========

3.99741673 ======== ReloadInfo ========

4,99728107 ^^^^^^^^ OnTime ^^^^^^^^

4.99742365 ======== LockInfo ========

4.99744749 ======== ReloadInfo ========

5,99728870 ^^^^^^^^ OnTime ^^^^^^^^

5.99742651 ======== LockInfo ========

5.99744844 ======== ReloadInfo ========

Tässä OnTime on hetki, jolloin OnTimer-ajastinmenettely otettiin käyttöön, LockInfo on hetki, jolloin tiedon päivittämisestä vastaava säie heräsi, ReloadInfo on hetki, jolloin tiedot todella päivitettiin.

Kuten siepauksesta näkyy, kahdessa ensimmäisessä sekunnissa jaksollisuus ei ole korkealla tasolla, mutta sitten tilanne tasaantuu ja tarkkuus paranee, kuten todettu, yhteen millisekuntiin.

Kaikkien näiden toimien jälkeen ajastin alkaa vihdoin:

LARGE_INTEGER dueTime = RtlConvertLongToLargeInteger(0);

BOOLEAN olemassa = KeSetTimerEx(g_pTimer, dueTime, g_timerPeriod, g_pTimerDpc);

Tässä dueTime on aika ennen ensimmäistä OnTime()-proseduurin kutsua, ja g_timerPeriod on lisäkutsujen jakso.

Lopuksi DriverEntry-menettelyssä tämän ohjaimen kuvaajan vastaanottaneiden asiakassovellusten laskuri nollataan: pDeviceExtension->clientCount = 0;

Tämän yhden muuttujan ansiosta on mahdollista käyttää samanaikaisesti useiden käyttäjäsovellusten ajureita kerralla. Ainoa rajoitus heille on yksinoikeus saada tietoa prosesseista ja niiden säikeistä.

3.1.2 DriverUnload

Tässä menettelyssä, jos ajuriasiakkaiden määrä on nolla, kaikki ajastimen toiminnan järjestämiseksi luodut objektit poistetaan, mitex, laiteobjekti ja sen symbolinen linkki poistetaan. Jos asiakkaiden määrä on eri kuin nolla, ajuria ei pureta, koska muuten se häiritsee muiden käyttäjien asiakassovellusten normaalia toimintaa.

3.1.3 DispatchCreate ja DispatchClose

Nämä funktiot ottavat huomioon CreateFile() API-kutsun avulla vastaanotettujen avoimien kuvaajien määrän tietylle ohjaimelle. Koska useita kahvoja on avattu, sama numero on suljettava CloseHandle() API -kutsulla. Muuten ajuri jää käyttöjärjestelmään sen jälkeen, kun käyttäjäsovellus on päättynyt, mikä on tietysti erittäin ei-toivottavaa.

3.1.4 DispatchDeviceControl

Tämä menettely palvelee DeviceIoControl() API -kutsun lähettämiä IOCTL-pyyntöjä käyttäjäsovelluksista. Tässä kurssiprojektissa vuorovaikutus kuljettajan kanssa perustuu pääosin heidän käyttöönsä tässä toteutetaan kuljettajan päätoiminto: mihin se on tarkoitettu; Siksi tämä menettely on laajin.

Ensin, riippuen tietystä IOCTL-pyynnöstä, saadaan osoitin ajurilaiteobjektille tarkoitetun IRP-paketin IRP-pinosoluun:

PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);

Tarkasteltavassa ajurissa kaikki IOCTL-pyynnöt käyttävät puskuroitua tiedonsiirtomenetelmää, koska kaikissa pyynnöissä niiden määrä on todella pieni. Tämä tiedonsiirtotapa varaa tarpeeksi muistia järjestelmän sivuvarastossa suuremman syöttö- ja lähtöpuskurin vastaanottamiseksi. Ennen kuin pyyntö alkaa käsitellä, syötetyn käyttäjäpuskurin sisältö kopioidaan järjestelmäpuskuriin ja sen valmistuttua järjestelmäpuskurista - lähtökäyttäjäpuskuriin. Koska molemmissa käyttäjäpuskureissa käytetään vain yhtä järjestelmäpuskuria, sinun on oltava varovainen tietojen käsittelyssä, koska on mahdollista, että kirjoitettaessa se vahingoittaa lukematonta syöttötietoa ja sitten se katoaa lopullisesti.

Käyttäjäpuskurien, tulon ja lähdön, pituudet (tavuina) haetaan IRP-pinosolun Parameters-kentästä: Parameters.DeviceIoControl.InputBufferLength ja Parameters.DeviceIoControl.OutputBufferLength. Ja järjestelmän puskurin osoite poimitaan IRP-paketin otsikosta: AssociatedIrp.SystemBuffer.

Viikonloppuetiedot: [ei]

Tätä IOCTL-pyyntöä käytetään yhteydenottoon kuljettajaan, jotta se vastaa kysymykseen, onko pyynnön aloittaja ainoa asiakas, joka työskentelee kuljettajan kanssa tällä hetkellä. Jokainen käyttäjäsovellus lähettää tämän pyynnön kuljettajalle, kun se on poistumassa. Jos vastaus on kyllä, sovellus yrittää lopettaa ajurin, muuten se yksinkertaisesti lopettaa toimintansa varmana siitä, että ajurissa on käynnissä muita asiakkaita ja että viimeksi päättyvä sovellus huolehtii ajurin purkamisesta.

Viikonloppusetiedot: [ei]

Tämän ensimmäisen IOCTL-pyynnön avulla käyttäjäsovellus kaappaa järjestelmätiedot yksinomaiseen käyttöön. Toinen on vastaavasti tämän resurssin vapauttaminen. He kutsuvat yksinkertaisesti samannimistä LockInfo()- ja UnlockInfo()-funktiota, jotka kuvattiin aiemmin tässä osiossa puhuttaessa DriverEntry-menettelystä.

Viikonloppusetiedot: rakenne, jossa on perustiedot prosessista.

Tämä IOCTL-pyyntöpari sallii niiden aloittajan tarkastella peräkkäin rakenteita, jotka kuvaavat käynnissä olevia prosesseja järjestelmässä. Kukin niistä kutsuu samannimistä ProcessFirst()- ja ProcessNext()-funktiota, vastaavasti. Ensimmäinen toiminto asettaa osoittimen ensimmäiseen tietueeseen ja toinen siirtää osoittimen seuraavaan, jos sellainen on. Kunkin näiden toimintojen suorittamisen tuloksena on valmis rakenne, jossa on tiedot prosessista, jos luettelon loppua ei saavuteta. Mikäli listan loppu kuitenkin saavutetaan, IRP-paketti kuitenkin merkitään onnistuneesti käsitellyksi, mutta siirrettyjen tavujen määrän arvoksi asetetaan nolla, jolloin käyttäjäsovellus tunnistaa tilanteen oikein ja pysähtyy välittömästi. lähetetään lisää IOCTL_PROCESS_NEXT ajuripyyntöihin.

Viikonloppusetiedot: rakenne, jossa on perustiedot säikeestä.

Kuten edellisessä kappaleessa, tämä IOCTL-pyyntöpari sallii niiden aloittajan tarkastella peräkkäin rakenteita, jotka kuvaavat valitun prosessin säikeitä. Näiden pyyntöjen käsittelyn logiikka on samanlainen kuin prosesseja koskevien tietojen hankkiminen.

3.1.4.6 IOCTL_OPEN_THREAD. Syötetiedot: käyttöoikeudet, kohdesäikeen yksilöllinen tunniste.

Viikonloppusetiedot: Kohdevirran kahva.

Tätä IOCTL-pyyntöä käsiteltäessä yritetään avata kahva säikeelle, jolla on määritetty tunniste käyttäjän asiakassovelluksen pyytämien oikeuksien kanssa.

Viikonloppusetiedot: [Ei].

Tämän IOCTL-pyynnön käsittelyn aikana yritetään sulkea säikeen kahva, joka avattiin aiemmin IOCTL_OPEN_THREAD-pyynnöllä.

3.1.4.7 IOCTL_GET_THREAD_CONTEXT. Syötetiedot: laitteistokontekstirakenne, kohdesäikeen kuvaaja.

Viikonloppusetiedot: laitteistokontekstirakenne.

Tämä IOCTL-pyyntö hyödyntää DeviceIoControl API -kutsua täyden hyödyn, koska tässä ovat mukana sekä syöttö- että lähtöpuskurit. Syöte on laitteistokontekstin rakenne, jossa on alustettu CONTEXT::ContextFlags-kenttä, joka osoittaa, mitkä laitteistokontekstirekisterien ryhmät tulee palauttaa tässä rakenteessa, kun pyyntö on suoritettu onnistuneesti. Tämä projekti kyselee koko laitteistokontekstia.

3.2 Mukautettu sovellus

Käyttäjäsovellus sisältää kaksi luokkaa: CDialog ja CDriver. Kuten nimet viittaavat, nämä luokat vastaavat vuorovaikutuksesta käyttäjän kanssa sovelluksen valintaikkunan kautta ja vuorovaikutuksesta kuljettajan kanssa ensisijaisesti IOCTL-pyyntöjen kautta.

Kun käyttäjäsovellusinstanssi käynnistyy, se yrittää ensimmäisenä asentaa ohjaimen, ellei toinen ilmentymä ole aiemmin tehnyt tätä. Jos asennus aiheutti virheen, käyttäjälle annetaan vastaava viesti, joka ilmoittaa tekstimuodossa tapahtumisen syyn, jos se oli säädetty, muussa tapauksessa sen koodi ilmoitetaan yksinkertaisesti. Käyttäjä voi pyytää ohjaimen asennusta uudelleen antamalla myönteisen vastauksen vastaavaan ohjelmatarjoukseen. Tämä toimenpide toistetaan, kunnes ohjaimen asennus onnistuu tai käyttäjä kieltäytyy yrittämästä uudelleen.

Tämän jälkeen ladataan avattava luettelo käynnissä olevista prosesseista, lajiteltu aakkosjärjestykseen niiden nimien mukaan, listasta valitaan ensimmäinen prosessi ja sen säikeet näytetään toisessa avattavassa luettelossa. Nämä luettelot päivitetään aina, kun käyttäjä haluaa valita eri prosessin tai säikeen, koska hän tarvitsee uusimmat tiedot tehdäkseen niin.

Nämä tiedot saadaan ohjaimien kautta, kuten jo mainittiin, käyttämällä DeviceIoControl API -kutsua:

BOOL DeviceIoControl

(HANDLE hDevice,

DWORD dwIoControlCode,

LPVOID lpInBuffer, DWORD nInBufferSize,

LPVOID lpOutBuffer, DWORD nOutBufferSize,

LPDWORD lpBytesReturned,

LPOVERLAPPED lpPäällekkäinen);

HANDLE hDevice - sen laitteen kuvaus, johon pyyntö lähetetään;

DWORD dwIoControlCode - IOCTL-pyyntökoodi;

LPVOID lpInBuffer - syöttöpuskurin osoite;

DWORD nInBufferSize - syöttöpuskurin pituus;

LPVOID lpOutBuffer - lähtöpuskurin osoite;

DWORD nOutBufferSize - lähtöpuskurin pituus;

LPDWORD lpBytesReturned - siirrettyjen tavujen määrä;

LPOVERLAPPED lpOverlapped on asynkronista kyselyn suorittamista käytettäessä vaadittava rakenne, jota ei ole tässä sovelluksessa.

Tämän API-kutsun käyttö on täysin kapseloitu CDriver-luokkaan, joka toteuttaa jokaiselle pyynnölle erillisen menetelmän, jonka nimi on samanlainen kuin IOCTL-pyynnön nimi, mikä tarjoaa intuitiivisen käsityksen tämän luokan käyttöliittymästä.

Tämä luokka sisältää myös Service Control Managerin (SCM) käytön, jota käytetään ohjaimen dynaamiseen asentamiseen, käynnistämiseen, pysäyttämiseen ja poistamiseen.

4. Tekninen osa

4.1 Käyttöjärjestelmän ja ohjelmointiympäristön valinta

Käyttöjärjestelmäksi valittiin Windows. Tämä johtuu siitä, että DOS-käyttöjärjestelmä on jo vanhentunut monista syistä (olemme jo siirtyneet pois yhden tehtävän käyttöjärjestelmistä), eikä henkilökohtaisille koneille ole olemassa muita käyttöjärjestelmiä, joissa on hyvä käyttöliittymä ja jotka olisivat todella käyttäjäystävällisiä. ystävällinen. Windows on edelleen yleisin PC-käyttöjärjestelmä. Lisäksi erilaisia ​​ohjelmistokehitysympäristöjä on suunniteltu erityisesti Windowsille:

Visual C++, Visual Basic, Borland C++ Builder, Delphi ja muut.

Käyttäjäohjelman kirjoituskieleksi valittiin C++. C++-kieli tarjoaa erittäin runsaasti mahdollisuuksia ohjelmoijille ja on kenties yleisin heidän ympäristössään. Se on erittäin tehokas operaattorikieli. Lisäksi se tarjoaa riittävän vapauden ohjelmien kirjoittamiseen, kun taas Pascal asettaa hyvin kapeat rajat erityisesti muuttujien kuvaukseen eikä salli monimutkaisten operaattorilausekkeiden rakentamista. Ajurin kirjoituskieleksi valittiin C. Tämän kielen käyttö varmistaa siirrettävyyden järjestelmien välillä: ajurin uudelleenrakentaminen on maksimissaan. Microsoft Visual Studio .Net valittiin kehitysympäristöksi, koska se tarjoaa tehokkaat ja kätevät työkalut ohjelmistotuotteen käyttöliittymän visuaaliseen kehittämiseen, mutta myös projektien perustamiseen, mikä mahdollistaa työpaikan tehokkaan organisoinnin.

4.2 Käyttöliittymä

Mukautetun Profiler-sovelluksen ilmentymän ikkuna näyttää tältä:

Valintaikkunan yläreunassa on kaksi avattavaa luetteloa, joiden yläosassa näkyy luettelo käynnissä olevista prosesseista järjestelmässä ja alaosassa - luettelo tämän prosessin säikeistä. Näitä ohjaimia voidaan käyttää kertomaan sovellukselle, mitä prosessia ja mitä prosessin säiettä valvotaan.

Dialogissa on kolme ryhmää:

Ryhmä "Prosessitiedot":

ProcessID - prosessin tunniste;

ParentID - vanhempi prosessin tunniste;

BasePriority - oletusperusprioriteetti prosessisäikeille;

ThreadCount - prosessisäikeiden lukumäärä;

KernelTime - prosessisäikeiden kerneltilassa vietetty kokonaisaika, 1 yksikkö vastaa 100 ns;

UserTime - prosessisäikeiden käyttäjätilassa vietetty kokonaisaika, 1 yksikkö on 100 ns.

Ryhmä "Striimin tiedot":

ThreadID - säikeen tunniste;

BasePriority - säikeen perusprioriteetti;

Priority - langan prioriteetti;

ContextSwitches - säikeen suorittamien kontekstin vaihtojen määrä;

KernelTime - ydintilassa vietetty aika (1 yksikkö vastaa 100 ns);

UserTime - käyttäjätilassa vietetty aika (1 yksikkö vastaa 100 ns).

WaitTime - hetki, jolloin säie siirtyi odotustilaan (lasketaan järjestelmän käynnistymisestä).

Viestiketjun kontekstiryhmä:

Tämä edustaa säikeen laitteistokontekstia. Useimmat sovellukset odottavat syötteitä käyttäjältä. Kun seuraat tällaisen prosessin säikeitä, et välttämättä näe muutoksia ollenkaan. Siksi visuaalisemman yleiskuvan saamiseksi kannattaa suorittaa tehtäviä, jotka vaativat suuria laskentakustannuksia. Esimerkiksi WinAmp, jolla voit soittaa musiikkia - tästä vastuussa oleva säie näkyy välittömästi muuttamalla yleiskäyttöisiä rekistereitä. Mutta yleisimmät muutokset rekistereihin eri tarkoituksiin tapahtuvat todella "raskaissa" tehtävissä, esimerkiksi tietokonegrafiikasta voi suorittaa kurssiprojektin.

4.3 Laitteistovaatimukset

Ohjain on kirjoitettu Windows NT versiolle 5.x.

Useiden käyttäjien asiakassovellusten pyyntöjen käsittelyä on testattu vain Windows XP Service Pack 2:ssa.

Johtopäätös

Projektin parissa tehdyn työn tuloksena otettiin käyttöön mukautettu sovellus, joka on vuorovaikutuksessa Legacy-ohjaimen kanssa. Sen avulla se saa perustiedot valitusta prosessista, perustiedot ja määritetyn prosessin valitun säikeen laitteistokontekstin. Tämä sovellus on perusta täysimittaisten sovellusprofiilien toteuttamiselle kohdesovellusten jäljittämiseksi ja niiden pullonkaulojen havaitsemiseksi, mikä voi merkittävästi lisätä ohjelmoijan ja hänen kehittämänsä ohjelmiston tehokkuutta.

Luettelo käytetystä kirjallisuudesta

1. V.P. Soldatov "Windows-ohjainohjelmointi". Ed. 3., tarkistettu ja ylimääräisiä - M.: Binom-Press LLC, 2006 - 576 s.: ill.

2. M. Russinovich, D. Solomon "Microsoft Windows Internals: Windows Server 2003, Windows XP ja Windows 2000", 4. painos.

3. J. Richter "Windows ammattilaisille: tehokkaiden Win32-sovellusten luominen ottaen huomioon Windowsin 64-bittisen version erityispiirteet" / Käännetty, Englanti - 4. painos. - Pietari; Pietari; M.: Kustannus- ja kauppatalo "Russian Edition", 2001.

4. Schreiber, Sven B., 1958 - Dokumentoimattomat Windows 2000 -salaisuudet: ohjelmoijan keittokirja.

5. Garry Nebbett, Windows NT/2000 Native API.

Samanlaisia ​​asiakirjoja

    Modulaarisen ohjelmoinnin tärkeimmät edut. Toimenpiteen valinta: taulukon syöttäminen konsolista, taulukon näyttäminen, tiedot tekijästä ja ratkaistavan ongelman tilasta ennen käsittelyä ja käsittelyn jälkeen. Proseduurien hierarkia, moduulien tarkoituksen ominaisuudet.

    tiivistelmä, lisätty 29.1.2016

    Keskeytyksen käsitteen, vektorien ja mekanismien tutkiminen; niiden luokittelu alkuperälähteen mukaan. Käyttöjärjestelmän laitteisto- ja ohjelmistoosien vastauksen ominaisuudet signaaleihin jonkin tietokoneen tapahtuman esiintymisestä.

    tiivistelmä, lisätty 22.6.2011

    Analyysi olemassa olevista teknologioista verkkosovellusten luomiseen. Verkkoteknologian kehittäminen lastentarhassa nro 176 "Belochka" olevien lasten tietojen julkaisemiseen ja käsittelyyn käyttämällä JSP-sivuja ja servlettejä JDBC-ajurin avulla tietokantaan pääsyä varten.

    kurssityö, lisätty 18.12.2011

    Tiedon tallennus- ja käsittelyjärjestelmän ja rajapinnan kehittäminen. Xamarin.Forms-teknologian avulla rahtikirjojen täyttö järjestetään. Käyttöjärjestelmän, kielen ja ohjelmointiympäristön valinta. Tietojärjestelmän laitteistointegrointi.

    opinnäytetyö, lisätty 7.9.2017

    Keskeytyksen käsittelyn periaatteet ja algoritmit. Joukko toimenpiteitä mikroprosessorin keskeytyksen käsittelyvaiheiden toteuttamiseksi. Resident-ohjelman rakenteen ja algoritmin kehittäminen. Ohjelman toteutus Assembly-kielellä, menetelmät sen virheenkorjaukseen ja testaukseen.

    kurssityö, lisätty 22.12.2014

    Esimerkki ohjelman rakentamisesta aritmeettisilla operaattoreilla. Perustyökalut laskimen luomiseen. Menettely numeroiden syöttämiseksi. "+"-painikkeen painamisen käsittelytapa on muutettu. Ohje-lomakkeen avaamismenettely, lopputulos.

    esitys, lisätty 3.2.2012

    Keskeytyksen käsittelymekanismin suunnittelu. Intel 82C59A keskeytysohjain. Keskeytä I/O. Intel 82C55A ohjelmoitava liitäntäohjain. Prosessorin rooli I/O-keskeytysten käsittelyssä. Yleiskatsaus keskeytyksen käsittelyalgoritmiin.

    testi, lisätty 19.5.2010

    Simulaatiomallinnuksen tulosten vertailu ja ominaisuuksien analyyttinen laskeminen. Tietopakettien kytkentäsolmun tutkimus, pakettien käsittely prosessorissa, puskurointi ja siirto lähtölinjaa pitkin. Prosessorin kuormituskertoimen määrittäminen.

    kurssityö, lisätty 29.6.2011

    Taloudellisten tietojenkäsittelyjärjestelmien vaatimukset ja rakenne. Tietojenkäsittelytekniikka ja järjestelmien ylläpito, tiedon suojaus. Kyselyjen, lomakkeiden, raporttien, makrojen ja moduulien luontiprosessi. Työkaluja tietokantojen järjestämiseen ja niiden kanssa työskentelyyn.

    kurssityö, lisätty 25.4.2012

    Perustekniikat Delphi-ohjelmointiympäristössä työskentelyyn. Tekniikan ominaisuudet yksinkertaisten sovellusten luomiseen. Työskentely sovelluskehitysympäristön komponenttien kanssa. Tietojen syöttö, muokkaus, valinta ja tulostus. Haaroittumisrakenteen käytön näkökohdat.

Sen lisäksi, että IRQL dispatch_leveliä käytetään ajamaan NT Dispatcheria, sitä käytetään myös käsittelemään viivästettyjen menettelyjen kutsuja (DPC). DPC-kutsut ovat takaisinkutsuja rutiineihin, jotka suoritetaan dispatchjevelin IRQL:llä. DPC-kutsuja pyydetään yleensä korkeammista IRQL-tasoista edistyneen, ei-aikakriittisen käsittelyn suorittamiseksi.

Katsotaanpa pari esimerkkiä siitä, milloin DPC:itä käytetään. Windows NT -laiteajurit suorittavat hyvin vähän käsittelyä keskeytyspalvelurutiineissaan. Sen sijaan, kun laite keskeytyy (DIRQL-tasolla) ja sen ajuri määrittää, että monimutkaista käsittelyä tarvitaan, ohjain pyytää DPC:tä. DPC-pyyntö saa tietyn ohjaintoiminnon takaisinkutsun dispatch_level IRQL -tasolla suorittamaan loppuosan vaaditusta käsittelystä. Suorittamalla tämän käsittelyn IRQL-lähetystasolla ajuri viettää vähemmän aikaa DIRQL-tasolla ja vähentää siksi keskeytysviivettä kaikille muille järjestelmän laitteille.

Kuvassa Kuva 15 esittää tyypillisen tapahtumasarjan.

Ensin ISR pyytää DPC:tä ja NT sijoittaa DPC-objektin kohdeprosessorin jonoon. DPC-prioriteetista ja DPC-jonon pituudesta riippuen NT luo DPC-ohjelmistokeskeytyksen välittömästi tai jonkin ajan kuluttua. Kun prosessori tyhjentää DPC-jonon, DPC-objekti poistuu jonosta ja ohjaus siirtyy sen DPC-toimintoon, joka päättää keskeytyksen käsittelyn lukemalla tietoja keskeytyksen luoneesta laitteesta tai kirjoittamalla siihen tietoja.
Toinen yleinen DPC:n käyttötarkoitus on ajastinrutiinit. Kuljettaja voi pyytää tietyn toiminnon suorittamista ilmoittamaan, kun tietty aika on kulunut (tämä tehdään KeSetTimer()-funktiolla). Kellon keskeytysrutiini valvoo ajan kulumista ja tietyn ajan kuluttua pyytää DPC:tä kuljettajan määrittämälle rutiinille. DPC:n käyttäminen ajastettuihin ilmoituksiin sallii kellon keskeytysrutiinin palata nopeasti, mutta silti johtaa tiettyyn rutiiniin kutsumiseen ilman tarpeetonta viivettä.

DPC-objekteja

DPC-kutsu kuvataan DPC-objektilla. DPC-objektin (KDPC) määritelmä on tehty tiedostossa ntddk.h ja se on esitetty kuvassa. 16.

Riisi. 16. DPC-objekti

Ajuri voi varata DPC-objektin mistä tahansa sivuttamattomasta tilasta (kuten sivuttamattomasta poolista). DPC-objektit alustetaan KelnitializeDpc()-funktiolla, jonka prototyyppi on:

VOID KelnitializeDpc (IN PKDPC Dpc,
IN PKDEFERRED^RUTINE DeferredRutine,
IN PVOID DeferredContext);

Missä:
Dpc - Osoitin DPC-objektiin, joka on alustettava; DeferredRoutine - osoitin toimintoon, johon lykätty puhelu tulee tehdä IRQL DISPATCH_LEVEL -tasolla. DeferredRutine-funktion prototyyppi on seuraava:

VOID (*PKDEFERRED_ROUTINE)(
PKDPC Dpc:ssä,
IN PVOID DeferredContext,
IN PVOID SystemArgumentI,
IN PVOID SystemArgument2);

Missä:
DeferredContext – arvo, joka välitetään DeferredRutinen parametrina, sekä osoitin DPC-objektiin ja kaksi muuta parametria.
Tietyn DPC-rutiinin suorittamista koskeva pyyntö tehdään sijoittamalla DPC-objekti, joka kuvaa kyseistä DPC-rutiinia tietyn CPU:n DPC-jonoon, ja sitten (yleensä) pyytämällä ohjelmiston IRQL-keskeytystä.
lähetystaso. Prosessoria kohden on yksi DPC-jono. CPU, johon DPC-objekti on jonossa, on yleensä nykyinen prosessori, jolla (keskeytys)pyyntö lähetetään. Prosessorin valintaa tietylle DPC:lle käsitellään myöhemmin DPC-objektin ominaisuudet -osiossa. DPC-objekti asetetaan jonoon KelnsertQueueDpc()-funktiolla, jonka prototyyppi on:

VOID KelnsertQueueDpc (IN PKDPC Dpc,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2);

Missä:
Dpc - Osoittaa jonossa olevaan DPC-objektiin;
SystemArgumentl, SystemArgument2 ovat mielivaltaisia ​​arvoja, jotka on välitettävä DeferredRoutme-funktiolle parametreina 3 ja 4, sekä osoitin DPC-objektiin ja DeferredContext-parametri, jotka määritettiin DPC-objektin alustuksen yhteydessä.

DPC:n aktivointi ja ylläpito

Dispatch_level-ohjelmistokeskeytyksen alkuperä tunnistetaan, kun keskeytyksestä tulee korkein kyseisessä prosessorissa odottava IRQL-tapahtuma. Siten KelnsertQueueDpc()-funktion kutsumisen jälkeen prosessori tyypillisesti seuraavan kerran, kun se on valmis palaamaan lähetystason alapuolella olevaan IRQL:ään, sen sijaan se palaa dispatch_level IRQL:ään ja yrittää käsitellä DPC-jonon sisältöä.
Kuten aiemmin tässä luvussa todettiin, IRQL DISPATCHJLEVELiä käytetään sekä DPC-jonon lähettämiseen että käsittelyyn. NT 4.0:ssa, kun DISPATCH_LEVEL-keskeytystä huolletaan, koko DPC-jono huolletaan ensin, ja sitten Dispatcheria kutsutaan ajoittamaan seuraava säie suoritettavaksi. Tämä on järkevää, koska DPC-rutiinin suorittama prosessointi voi muuttaa säikeen ajoitustietokannan tilaa esimerkiksi saattamalla aiemmin odottavan säikeen toimimaan.
DPC-jonoa ylläpitää mikroydin. Joka kerta kun DPC-jonoa huolletaan, kaikki nykyisen prosessorin DPC-jonon elementit käsitellään. Mikrokernel poistaa DPC-objektin yksi kerrallaan jonon päästä ja kutsuu objektissa määritettyä DeferredRutinea. Mikroydin välittää parametreina DeferredRoutine-funktiolle osoittimen DPC-objektiin, DPC-objektin DeferredContext-, SystemArgumentl- ja SystemArgument2-kenttien sisältöön.
Koska DPC-jonoa palvellaan IRQL-lähetystasolla, DPC-rutiineja kutsutaan IRQL-lähetystasolla. Koska DPC-jonoa huolletaan aina, kun dispatch_level IRQL on korkeimman prioriteetin IRQL palvelulle (esimerkiksi välittömästi keskeytyskäsittelijän suorittamisen jälkeen ja ennen paluuta keskeytettyyn käyttäjäsäikeeseen), DPC-toiminnot toimivat mielivaltaisessa säikeessä. Mielivaltaisella säikeen kontekstilla tarkoitamme, että DPC suoritetaan prosessissa ja säikeessä, joilla ei ehkä ole mitään tekemistä DPC:n käsittelemän pyynnön kanssa. (Suorituskonteksti on kuvattu tarkemmin "Layered Driver Model" -osiossa.)
DPC-rutiini suorittaa käsittelyn ja palauttaa. Palattuaan DPC-rutiinista mikrokernel yrittää valita toisen DPC-objektin DPC-jonosta ja käsitellä sitä. Kun DPC-jono on tyhjä, DPC-käsittely päättyy. Mikroydin etenee soittamaan Dispatcherille (scheduler).

Lukuisia pyyntöjä DPC:lle

Jokainen DPC on kuvattu tietyllä DPC-objektilla. Tämän seurauksena aina kun KelnsertQueueDpc():tä kutsutaan ja sille välitetyn DPC-objektin havaitaan olevan jo samassa DPC-jonossa, KelnsertQueueDpcQ yksinkertaisesti palaa (tekemättä mitään). Näin ollen aina kun DPC-objekti on jo DPC-jonossa, kaikki myöhemmät yritykset asettaa sama DPC-objekti jonoon ennen kuin DPC-objekti poistetaan jonosta, ohitetaan. Tämä on järkevää, koska DPC-objekti voidaan fyysisesti sisällyttää vain yhteen DPC-jonoon kerrallaan.
Ilmeinen kysymys, joka voi syntyä, on: Mitä tapahtuu, kun DPC-objektin asettaminen jonoon pyydetään, mutta järjestelmä suorittaa jo kyseisen DPC-objektin määrittämää DPC-rutiinia (samalla tai eri prosessorilla)? Vastaus tähän kysymykseen löytyy lukemalla huolellisesti edellinen osa. Kun Microkernel palvelee DPC-jonoa, se poistaa DPC-objektin jonon päästä ja kutsuu vasta sitten DPC-objektin määrittämää DPC-rutiinia. Näin ollen kun DPC-rutiinia kutsutaan, DPC-objekti on jo poistettu prosessorin DPC-jonosta. Siksi, kun pyyntö jonottaa DPG-objekti ja järjestelmä on kyseisessä DPC-objektissa määritellyn DPC-rutiinin sisällä, DPC asetetaan jonoon normaalisti.

DPC moniprosessorijärjestelmissä

Toisin kuin joissakin muussa kirjallisuudessa on todettu, ja kuten edellisestä keskustelusta pitäisi olla selvää, sama DPC-rutiini voidaan suorittaa useilla prosessoreilla samanaikaisesti. Mikroytimen puolella ei ole mitään estoa tämän estämiseksi.
Harkitse tapausta laiteohjaimesta, jolla on useita vireillä olevia pyyntöjä samanaikaisesti. Ohjainlaite keskeyttää prosessorissa 0, ohjaimen keskeytyskäsittelijä suorittaa ja pyytää DPC:tä viimeistelemään keskeytyksen käsittelyn. Tämä on vakiopolku, jota ajurit seuraavat Windows NT:ssä. Kun keskeytyskäsittelijä poistuu ja järjestelmä on valmis palaamaan keskeytettyyn käyttäjäsäieteen, prosessorin O:n IRQL lasketaan DIRQL:stä, jossa ISR suoritettiin, dispatch_level IRQL:lle. Tämän seurauksena Microkernel palvelee DPC-jonoa poistamalla ajurin DPC-objektin ja kutsumalla siinä määritettyä DPC-rutiinia. Prosessori 0 suorittaa nyt DPC-ohjainrutiinia.
Välittömästi DPC-ohjainrutiinin kutsumisen jälkeen laite luo keskeytyksen uudelleen. Tällä kertaa keskeytystä kuitenkin palvellaan vain laitteiston tuntemista syistä prosessorissa 1. Ajurin keskeytyksen käsittelijä pyytää jälleen DPC:tä. Ja jälleen, kun keskeytysrutiini päättyy, järjestelmä (prosessori 1) on valmis palaamaan keskeytettyyn käyttäjäsäieteen. Tässä tapauksessa prosessorin 1 IRQL lasketaan dispatch_level IRQL:lle ja Microkernel palvelee DPC-jonoa. Näin tehdessään (ja edelleen suorittimessa 1) mikroydin poistaa DPC-ohjainobjektin ja kutsuu DPC-ohjainrutiinia. DPC-ajurin rutiini on nyt käynnissä prosessorissa 1. Olettaen, että DPC-ohjainrutiini ei ole vielä päättynyt suorittimessa 0, huomaa, että sama DPC-rutiini toimii nyt rinnakkain molemmissa prosessoreissa.
Tämä esimerkki korostaa oikeanlaisen moniprosessorin synkronointimekanismien käytön tärkeyttä ohjaimissa. Erityisesti DPC-toiminnon on käytettävä spinlockeja sarjoittamaan pääsy kaikkiin tietorakenteisiin, joita on käytettävä yhtenä yksikkönä, edellyttäen, että ajurin rakenne on sellainen, että useita DPC-kutsuja voi esiintyä samanaikaisesti.

DPC-objektin ominaisuudet

DPC-objekteilla on kaksi ominaisuutta, jotka vaikuttavat niiden käsittelytapaan. Nämä ominaisuudet ovat tärkeys- ja numerokentät.

DPC:n tärkeys (DPC-tärkeys)

Jokaisella DPC-objektilla on tärkeys, joka tallennetaan DPC-objektin Tärkeys-kenttään. Tämän kentän arvot on lueteltu ntddk.h:ssa nimillä Highlmportance, Mediumlmportance ja Lowlmportance. Tämän objektin DPC-arvo vaikuttaa siihen, mihin kohtaan DPC-jonossa DPC-objekti sijoitetaan, kun se asetetaan jonoon, sekä siihen, tapahtuuko IRQL-lähetystason keskeytys, kun DPC-objekti asetetaan jonoon. KelnitializeDpc()-funktio alustaa DPC-objektit, joiden tärkeys on Mediumlmforance. DPC-objektin tärkeysarvo voidaan asettaa KeSetlmportanceDpc()-funktiolla, jonka prototyyppi on:

VOID KeSetlmportanceDpc (IN PKDPC Dpc,
KDPCIMPORTANCE Tärkeys);

Missä:
Dpc - Osoitin DPC-objektiin, jossa Tärkeys-kenttä tulee asettaa;
Tärkeys - DPC-objektiin asennettava tärkeysarvo.
DPC-objektit, joiden merkitys on keskikokoinen tai pieni, sijoitetaan DPC-jonon loppuun. DPC-objektit, joissa on Highlmportance, sijoitetaan DPC-jonon alkuun.
DPC-objektien tärkeys vaikuttaa myös siihen, syntyykö dispatch_level-ohjelmistokeskeytys, kun DPC-objekti on jonossa. Kun DPC-objekti, jonka merkitys on suuri tai keskipitkä, on jonossa nykyisessä prosessorissa, generoidaan aina dispatchjevel-keskeytys. Dispatch_level-keskeytys luodaan pienitehoisille DPC:ille tai niille DPC:ille, jotka on tarkoitettu eri prosessorille kuin nykyinen prosessori, monimutkaisen (ja dokumentoimattoman) ajoitusalgoritmin mukaisesti.
Taulukko 11 luettelee tilanteet, jotka laukaisevat DPC-objektijonon vapauttamisen.
Useimpien laiteohjainten ei koskaan tarvitse asettaa DPC-objektien tärkeyttä. Harvinaisissa tapauksissa, joissa DPC-pyynnön ja DPC-suorituksen välinen viive on liian suuri ja ohjaimen kehittäjä ei pysty ratkaisemaan viivettä muulla tavalla, voit yrittää asettaa objektin DPC:n arvoon Highlmportance. Windows NT -laiteohjaimet eivät kuitenkaan yleensä muuta DPC-arvoaan oletusarvoisesta Mediumlmportancesta.

Taulukko 11. Tilanteet, jotka käynnistävät DPC-jonon tyhjennyksen

DPC-prioriteetti

DPC:t toimivat samalla prosessorilla kuin ISR:t

DPC:t suoritetaan eri prosessorilla

Lyhyt

DPC-jonon koko on suurempi kuin maksimi, DPC-pyyntönopeus on pienempi kuin minimi tai järjestelmä on käyttämättömänä

DPC-jonon koko ylittää enimmäismäärän tai järjestelmä on käyttämättömänä (tyhjäsäike käynnissä)

DPC voidaan rajoittaa suorittamaan tietyllä prosessorilla KeSetTargetProcessorDpc()-funktiolla, jonka prototyyppi on:

VOID KeSetTargetProcessorDpc(IN PKDPC Dpc,
IN CCHAR Numero);

Missä:
Dpc - Osoittaa DPC-objektiin, jolle kohdeprosessori tulisi asettaa;
Numero - sen prosessorin nollaperusteinen numero, jolle DPC tulee suorittaa.
DPC:n tärkeyden tavoin laiteohjain ei juuri koskaan määritä kohde-DPC-suoritinta. Oletusarvo, joka pakottaa DPC:n toimimaan nykyisellä prosessorilla, on lähes aina toivottava.
Kun DPC-objekti asetetaan tietylle kohdeprosessorille, tämä DPC-objekti sijoitetaan aina määritetyn prosessorin DPC-jonoon. Siten esimerkiksi vaikka KelnsertQueueDpc():tä kutsutaan prosessorissa 0, DPC-objekti, jonka kohdeprosessori on asetettu prosessoriksi 1, lisätään prosessorin 1 DPC-jonoon.

Kuten aiemmin tässä luvussa on käsitelty, yleisin DPC:iden käyttö on keskeytyspalvelurutiinin (ISR) lopettaminen. Jotta laiteajurit voisivat tehdä DPC-pyyntöjä ISR-toimintojensa täydentämiseksi, I/O Manager määrittää erityisen DPC:n, jota voidaan käyttää tähän tarkoitukseen. Tämän DPC:n nimi on DpcForlsr.
I/O Manager lisää DPC-objektin jokaiseen luomaansa laiteobjektiin. Laiteohjain alustaa tämän sulautetun DPC-objektin, tyypillisesti kun ohjain ladataan ensimmäisen kerran, kutsumalla IoInitializeDpcRequest()-funktiota.
IoInitializeDpcRequest() ottaa syötteenä osoittimen laiteobjektiin, johon DPC-objekti on upotettu, osoittimen kutsuttavaan ohjainfunktioon ja kontekstiarvon, joka välitetään kyseiselle funktiolle. IoInitializeDpcRequest() puolestaan ​​kutsuu KelnitializeDpc():tä alustamaan upotetun DPC-objektin, välittäen ohjainfunktioosoittimen DeferredRoutine-parametrina ja kontekstiarvon DeferredContext-parametrina.
Pyydäkseen DPC:tä ISR:ltä ajuri yksinkertaisesti kutsuu loRequestDpc() ja välittää osoittimen laiteobjektille. IoRequestDpc() puolestaan ​​kutsuu KelnsertQueueDpc():tä laiteobjektiin upotetussa DPC-objektissa.
Koska kaikissa laiteajureissa on Device Objects ja kaikki keskeytyksiä käyttävät ajurit käyttävät myös DPC:tä, I/O Managerin DpcForlsr-mekanismin käyttö on erittäin kätevää. Itse asiassa useimmat Windows NT:n laiteohjaimet eivät koskaan kutsu suoraan KelnitializeDpc()- tai KelnsertQueueDpc()-funktioita, vaan kutsuvat sen sijaan loInitializeDpcRequest() ja IoRequestDpc().