Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Wanneer twee threads van uitvoering resources delen die tegelijkertijd kunnen worden geopend, hetzij op een uniprocessorcomputer of op een SMP-computer (symmetrische multiprocessor), moeten ze worden gesynchroniseerd. Als op een uniprocessorcomputer een driverfunctie toegang heeft tot een gedeeld middel en wordt onderbroken door een andere functie die wordt uitgevoerd op een hogere IRQL, zoals een ISR, moet het gedeelde middel worden beveiligd om racecondities te voorkomen die de resource in een ongedefinieerde staat achterlaat. Op een SMP-computer kunnen twee threads tegelijkertijd worden uitgevoerd op verschillende processors en proberen dezelfde gegevens te wijzigen. Dergelijke toegang moet worden gesynchroniseerd.
NDIS biedt kringvergrendelingen die u kunt gebruiken om de toegang tot gedeelde resources te synchroniseren tussen threads die op hetzelfde IRQL worden uitgevoerd. Wanneer twee threads die een resource delen op verschillende IRQL-niveaus draaien, biedt NDIS een mechanisme om tijdelijk het IRQL-niveau van de lagere draad te verhogen, zodat de toegang tot de gedeelde resource kan worden geserialiseerd.
Wanneer een thread afhankelijk is van het optreden van een gebeurtenis buiten de thread, is de thread afhankelijk van een melding. Een bestuurder moet bijvoorbeeld worden gewaarschuwd wanneer een bepaalde periode is verstreken, om het apparaat te controleren. Of een NIC-stuurprogramma (Network Interface Card) moet mogelijk een periodieke bewerking uitvoeren, zoals polling. Timers bieden een dergelijk mechanisme.
Gebeurtenissen bieden een mechanisme dat twee threads van uitvoering kunnen gebruiken om bewerkingen te synchroniseren. Een minipoortstuurprogramma kan bijvoorbeeld de interrupt op een NIC testen door naar het apparaat te schrijven. Het stuurprogramma moet wachten tot een interrupt het stuurprogramma op de hoogte stelt dat de bewerking is geslaagd. U kunt gebeurtenissen gebruiken om een bewerking te synchroniseren tussen de thread die wacht tot de interrupt is voltooid en de thread die de interrupt afhandelt.
In de volgende subsecties in dit onderwerp worden deze NDIS-mechanismen beschreven.
Spinlocks
Een spin lock biedt een synchronisatiemechanisme voor het beveiligen van resources die worden gedeeld door kernelmodusthreads die worden uitgevoerd op IRQL > PASSIVE_LEVEL in een uniprocessor of een multiprocessorcomputer. Een kringvergrendeling verwerkt synchronisatie tussen verschillende threads van uitvoering die gelijktijdig worden uitgevoerd op een SMP-computer. Een thread verkrijgt een kringvergrendeling voordat toegang wordt verkregen tot beveiligde resources. De spinvergrendeling voorkomt dat elke thread, behalve degene die de spinvergrendeling vasthoudt, de bron gebruikt. Op een SMP-computer probeert een thread die wacht op de spinlock-lussen de spinlock te verkrijgen totdat deze wordt vrijgegeven door de thread die de spinlock vasthoudt.
Een ander kenmerk van spinvergrendelingen is de bijbehorende IRQL. Een poging om een spinvergrendeling te verkrijgen verhoogt tijdelijk de IRQL van de aangevraagde thread naar de IRQL die aan de spinvergrendeling is gekoppeld. Hierdoor voorkomt u dat alle lagere IRQL-threads op dezelfde processor de uit te voeren thread preempteren. Threads op dezelfde processor, die op een hogere IRQL draaien, kunnen de uitvoerende thread onderbreken, maar deze threads kunnen de spinlock niet verkrijgen omdat deze een lagere IRQL heeft. Daarom kan, nadat een thread een spinvergrendeling heeft verkregen, geen andere thread de spinvergrendeling verkrijgen totdat deze is vrijgegeven. Een goed geschreven netwerkstuurprogramma minimaliseert de tijd dat een spinvergrendeling wordt vastgehouden.
Een typisch gebruik voor een spinvergrendeling is het beveiligen van een wachtrij. De functie voor verzenden van het minipoortstuurprogramma, MiniportSendNetBufferLists, kan bijvoorbeeld pakketten in de wachtrij plaatsen die aan het stuurprogramma zijn doorgegeven door een protocolstuurprogramma. Omdat andere stuurprogrammafuncties deze wachtrij ook gebruiken, moet MiniportSendNetBufferLists de wachtrij beveiligen met een kringvergrendeling, zodat slechts één thread tegelijk de koppelingen of inhoud kan bewerken. MiniportSendNetBufferLists verkrijgt de spinlock, voegt het pakket toe aan de wachtrij en laat vervolgens de spinlock los. Het gebruik van een spinlock zorgt ervoor dat de thread met de vergrendeling de enige thread is die de koppelingen van de wachtrij wijzigt, terwijl het pakket veilig aan de wachtrij wordt toegevoegd. Wanneer het minipoortstuurprogramma de pakketten uit de wachtrij haalt, wordt een dergelijke toegang beveiligd door dezelfde spinvergrendeling. Wanneer u instructies uitvoert waarmee de kop van de wachtrij of een van de verbindingsvelden van de wachtrij wordt gewijzigd, moet het stuurprogramma de wachtrij beveiligen met een spinlock.
Een chauffeur moet ervoor zorgen dat een wachtrij niet overbeschermd wordt. Het stuurprogramma kan bijvoorbeeld bepaalde bewerkingen uitvoeren (bijvoorbeeld het invullen van een veld met de lengte) in het door het netwerkstuurprogramma gereserveerde veld van een pakket voordat het het pakket in de wachtrij plaatst. Het stuurprogramma kan dit doen buiten de coderegio die wordt beveiligd door de spinlock, maar moet dit doen voordat het pakket in de wachtrij wordt geplaatst. Nadat het pakket in de wachtrij staat en de actieve thread de kringvergrendeling loslaat, moet het stuurprogramma ervan uitgaan dat andere threads het pakket onmiddellijk uit de wachtrij kunnen verwijderen.
Spin Lock-problemen voorkomen
Om een mogelijke impasse te voorkomen, moet een NDIS-stuurprogramma alle NDIS-spinvergrendelingen vrijgeven voordat een andere NDIS-functie dan een NdisXxxSpinlock functie wordt aangeroepen. Als een NDIS-stuurprogramma niet aan deze vereiste voldoet, kan er als volgt een impasse optreden:
Thread 1, die NDIS spin lock A bevat, roept een NdisXxx functie aan die NDIS spin lock B probeert te verkrijgen door de NdisAcquireSpinLock functie aan te roepen.
Thread 2, die NDIS spin lock B bevat, roept een NdisXxx functie aan die NDIS spin lock A probeert te verkrijgen door de NdisAcquireSpinLock functie aan te roepen.
Thread 1 en thread 2, die elk wachten tot de ander hun spinslot loslaat, komen vast te zitten.
Microsoft Windows-besturingssystemen leggen geen beperkingen op aan een netwerkstuurprogramma dat tegelijkertijd meer dan één spin lock vasthoudt. Als één sectie van de bestuurder echter probeert spinvergrendeling A te verkrijgen terwijl hij spinvergrendeling B vasthoudt, en een andere sectie probeert spinvergrendeling B te verkrijgen terwijl de spinvergrendeling A vasthoudt, resulteert dit in impasses. Als er meer dan één spinvergrendeling wordt verkregen, moet een bestuurder een impasse voorkomen door een overnamevolgorde af te dwingen. Dat wil gezegd dat als een bestuurder het verkrijgen van spinvergrendeling A afdwingt vóór spinvergrendeling B, de hierboven beschreven situatie niet zal optreden.
Het verkrijgen van een kringslot verhoogt de IRQL naar DISPATCH_LEVEL en slaat de oude IRQL op in de spinvergrendeling. Het loslaten van de spinlock stelt de IRQL in op de waarde die is opgeslagen in de spinlock. Omdat NDIS soms stuurprogramma's op PASSIVE_LEVEL invoert, kunnen er problemen optreden met de volgende codereeks:
NdisAcquireSpinLock(A);
NdisAcquireSpinLock(B);
NdisReleaseSpinLock(A);
NdisReleaseSpinLock(B);
Een driver mag om de volgende redenen geen spinvergrendelingen gebruiken in de volgende volgorde:
Tussen het vrijgeven van spin lock A en het vrijgeven van spin lock B, de code wordt uitgevoerd op PASSIVE_LEVEL in plaats van DISPATCH_LEVEL en is onderhevig aan ongepaste onderbreking.
Na het vrijgeven van spinlock B, wordt de code uitgevoerd op DISPATCH_LEVEL, waardoor de aanroepende code veel later een fout kan veroorzaken met een IRQL_NOT_LESS_OR_EQUAL stopfoutmelding.
Het gebruik van spinvergrendelingen heeft invloed op de prestaties en in het algemeen mag een bestuurder niet veel spinvergrendelingen gebruiken. Soms hebben functies die meestal verschillend zijn (bijvoorbeeld functies voor verzenden en ontvangen) kleine overlappingen waarvoor twee kringvergrendelingen kunnen worden gebruikt. Het gebruik van meer dan één kringslot kan een waardevolle afweging zijn om ervoor te zorgen dat de twee functies onafhankelijk van elkaar op afzonderlijke processors kunnen werken.
Timers
Timers worden gebruikt voor polling- of time-outbewerkingen. Een stuurprogramma maakt een timer en koppelt een functie aan de timer. De bijbehorende functie wordt aangeroepen wanneer de periode die is opgegeven in de timer verloopt. Timers kunnen eenmalig of periodiek zijn. Zodra een periodieke timer is ingesteld, blijft deze bij de vervaldatum van elke periode geactiveerd totdat deze expliciet is gewist. Elke keer dat deze geactiveerd wordt, moet een eenmalige timer opnieuw worden ingesteld.
Timers worden gemaakt en geïnitialiseerd door NdisAllocateTimerObject aan te roepen en in te stellen door NdisSetTimerObjectaan te roepen. Als een niet-periodic timer wordt gebruikt, moet deze opnieuw worden ingesteld door NdisSetTimerObjectaan te roepen. Een timer wordt gewist door NdisCancelTimerObjectaan te roepen.
Gebeurtenissen
Gebeurtenissen worden gebruikt om bewerkingen tussen twee threads van uitvoering te synchroniseren. Een gebeurtenis wordt toegewezen door een stuurprogramma en geïnitialiseerd door NdisInitializeEventaan te roepen. Een thread die wordt uitgevoerd op IRQL = PASSIVE_LEVEL roept NdisWaitEvent- aan om zichzelf in een wachtstatus te plaatsen. Wanneer een stuurprogrammathread op een gebeurtenis wacht, wordt een maximale tijd opgegeven waarop moet worden gewacht, evenals de gebeurtenis waarop moet worden gewacht. De wachttijd van de thread wordt voldaan wanneer NdisSetEvent- wordt aangeroepen, waardoor de gebeurtenis wordt gesignaleerd of wanneer het opgegeven maximale wachttijdsinterval verloopt, afhankelijk van wat zich het eerst voordoet.
Normaal gesproken wordt de gebeurtenis ingesteld door een medewerkende thread die NdisSetEventaanroept. Gebeurtenissen zijn ongemarkeerd wanneer ze worden aangemaakt en moeten worden ingesteld om wachtende threads te signaleren. Gebeurtenissen blijven gesignaleerd totdat NdisResetEvent wordt aangeroepen.