Spinlock védelmi rendszerek programozása

A spin-lock a legegyszerűbb szinkronizáló mechanizmus. A spin-lock rögzíthető. és felszabadult. Ha a spinlockot elfogták, egy későbbi kísérlet a spinlock bármely szálon való rögzítésére végtelen hurkot eredményez, és megpróbál egy spin-lock (busy-waiting thread) befogását. A ciklus akkor fejeződik be, amikor a spinzár előző tulajdonosa feloldja. A spin zárak használata többprocesszoros platformokon is biztonságban van, vagyis garantált, hogy ha két szálat egyszerre kérnek két processzoron, csak egy szál rögzíti azt.
A spin-blokkolás célja, hogy megvédje az adatokat, amelyek különböző, többek között magas IRQL-szinteken elérhetőek. Most képzeljük el ezt a helyzetet: az IRQL szinten működő kód PASSIVE_ LEVEL rögzítette a spinzárat egyes adatok biztonságos módosítására. A kód megszakadt kód magasabb IRQL DISPATCH_LEVEL, aki megpróbálta megragadni ugyanazt spin-lock, és következik a leírás a spin-lock lépett végtelen ciklusba vár kioldó. Ez a ciklus soha nem fog befejeződni, mert a spinlock rögzítő kódnak alacsonyabb IRQL szintűnek kell lennie, és soha nem lesz esélye végrehajtani! Ahhoz, hogy egy ilyen helyzet nem merült fel, egy olyan mechanizmust, amely nem teszi lehetővé a kód bizonyos szintű IRQL megszakítás kód alacsonyabb IRQL a pillanatban, amikor a kód alacsonyabb IRQL birtokolja a spinlock. Ilyen mechanizmus az, hogy növelje az aktuális IRQL szintet, amikor a spinlockot a spinlockhoz társított IRQL bizonyos szintjéig zárta, és a régi IRQL szintet helyreállította a kiadás időpontjában. Ebből következik, hogy a futó kód emelt szintű IRQL, nem jogosult hozzáférni az erőforrás által védett spin-lock, ha a szint IRQL spinlocks alacsonyabb IRQL szinten termelő hozzáférést az erőforrás kódot. Amikor megpróbálsz rögzíteni egy spinlock-ot ezzel a kóddal, az IRQL szintjét az IRQL spinzár szintjére kell csökkenteni, ami kiszámíthatatlan következményekhez vezet.
Az NT-ben kétféle spinzár található:

  • Normál centrifugálási zárak, amelyek speciális esete a spin-blokkoló I / O-kérés törlése, amelyet az I / O-kérelmek sorbaállításakor használnak (lásd az "I / O-kérelmek törlése" c. Részt).
  • Spin-lock megszakítási időzítés.

A szokásos spinzárral az IRQL DISPATCH_LEVEL kapcsolódik, azaz:

  • minden megragadási kísérletet az IRQL szintjén kell végrehajtani, ami kisebb vagy egyenlő a DISPATCH_LEVEL értékkel;
  • A spinlock lezárása esetén az aktuális IRQL szint a DISPATCH_LEVEL szintre emelkedik.

Az egyik DIRQL szint kapcsolódik a megszakítási szinkronizálás spin interlockjaihoz. A normál centrifugálók használatát az alábbiakban ismertetjük (az előző szakaszban leírt I / O-kérelmek törlésére szolgáló spinzárak kivételével). A megszakításos szinkronizáláshoz használt spin zárak használatát a megszakításos kezelés szakaszában ismertetjük.

A hagyományos spinzár használatával

  1. 1. VOID KeInitializeSpinLock (IN PKSPIN_LOCK SpinLock); Ez a funkció inicializálja a KSPIN_LOCK kernel objektumot. A spin-lock memóriát már ki kell osztani nem paging memóriában.
    2. VOID KeAcquireSpinLock (IN PKSPIN_LOGK SpinLock, OUT PKIRQL Oldlrql); Ez a funkció rögzíti a centrifugálást. A funkció nem fogja visszavezetni a vezérlést, amíg a zárolás nem sikerül. A függvény végén az IRQL szint a DISPATCH_LEVEL szintre emelkedik. A második paraméter visszaadja az IRQL szintet, amely a zár befogása előtt volt (meg kell <= DISPATCH_LEVEL).
    3. VOID KeReleaseSpinLock (IN PKSPINJLOCK SpinLock, OUT PKIRQL Newlrql); Ez a függvény felszabadítja a spinlock értéket, és beállítja az IRQL szintet a Newlrql paraméter értékére. Ezt a KeAcquireSpinLock () függvény által az Oldlrql paraméterben megadott értéknek kell megadnia.
    4. VOID KeAcquireLockAtDpcLevel (IN PKSPIN_LOCK SpinLock); Ez az optimalizált funkció rögzíti a spinlock kódot, amely már fut az IRQL szintjén DISPATCH_LEVEL. Ebben az esetben az IRQL szint változása nem szükséges. Egyprocesszoros platformon ez a funkció egyáltalán nem működik, mivel a szinkronizációt maga az IRQL architektúra biztosítja.
    5. VOID KeReleaseLockFromDpcLevel (IN PKSPIN_LOCK SpinLock); Ez a funkció kikapcsolja a spinlock kódot a KeAcquireLockAtDpcLevel () függvény segítségével. Egyprocesszoros platformon ez a funkció nem tesz semmit.

Példa hagyományos spin zárak használatára:

typedef struct _DEVICE_EXTENSION
KSPIN_LOCK spinlock> DEVICE_EXTENSION, * PDEVICE_EXTENSION;
*
NTSTATUS DriverEntry (.)
KelnitializeSpinLock (kiterjesztés-> spinlock);
NTSTATUS DispatchReadWrite (.)
KIRQL Oldlrql;
KeAcquireSpinLock (kiterjesztés-> spinlock, 01dlrql); // folyamatadatok, // spinzárral védve
KeReleaseSpinLock (kiterjesztés-> spinlock, Oldlrql);>

A holtpontok problémája

Ha a szál megint megpróbálja megragadni a spinlockot, belép egy végtelen várakozási hurokba - "lefagy". Ugyanez a helyzet akkor is, ha két szál két spinzárat használ. Az 1-es adatfolyam rögzíti az 1-es reteszelést, míg a 2. szál megragadja a 2. reteszelést. Az 1. patront megpróbálja rögzíteni a 2. reteszelést és a 2-es reteszelést. Mindkét szál "lefagy". Ez a helyzet kiterjeszthető tetszőleges számú áramlásra, széles körben ismert, és holtpontokat jelent.
A probléma megoldása nagyon egyszerű. Az összes rögzített zárolást egyidejűleg rögzítheti a lista a csökkenő sorrendben. Ha rögzíteni kell a zárakat, azokat meg kell ragadni a felsorolás sorrendjében. Így létrehoztuk a zárak hierarchiáját.

Kapcsolódó cikkek