Condividi tramite


Blocco di codice o dati paginabili

Alcuni driver in modalità kernel, ad esempio i driver seriali e paralleli, non devono essere residenti in memoria a meno che i dispositivi gestiti siano aperti. Tuttavia, purché sia presente una connessione o una porta attiva, una parte del codice driver che gestisce tale porta deve essere residente per il servizio del dispositivo. Quando la porta o la connessione non viene usata, il codice driver non è obbligatorio. Al contrario, un driver per un disco che contiene codice di sistema, codice applicazione o il file di paging del sistema deve essere sempre residente in memoria perché il driver trasferisce costantemente i dati tra il dispositivo e il sistema.

Un driver per un dispositivo usato sporadicamente (ad esempio un modem) può liberare spazio di sistema quando il dispositivo gestito non è attivo. Se si inserisce in una singola sezione il codice che deve essere residente per il servizio di un dispositivo attivo e se il driver blocca il codice in memoria mentre viene usato il dispositivo, questa sezione può essere designata come paginabile. Quando il dispositivo del driver viene aperto, il sistema operativo porta la sezione paginabile in memoria e il driver lo blocca fino a quando non è più necessario.

Il codice del driver audio cd di sistema usa questa tecnica. Il codice per il driver viene raggruppato in sezioni paginabili in base al produttore del dispositivo CD. Alcuni marchi potrebbero non essere mai presenti in un determinato sistema. Inoltre, anche se esiste un CD-ROM in un sistema, potrebbe essere accessibile raramente, quindi raggruppare il codice in sezioni tabellabili in base al tipo CD assicura che il codice per i dispositivi che non esistano in un determinato computer non verrà mai caricato. Tuttavia, quando si accede al dispositivo, il sistema carica il codice per il dispositivo CD appropriato. Il driver chiama quindi la routine MmLockPagableCodeSection , come descritto di seguito, per bloccare il codice in memoria mentre viene usato il dispositivo.

Per isolare il codice paginabile in una sezione denominata, contrassegnarlo con la direttiva del compilatore seguente:

#pragma alloc_text(PAGE*Xxx, *RoutineName)

Il nome di una sezione codici paginabile deve iniziare con le quattro lettere "PAGE" e può essere seguito da fino a quattro caratteri (rappresentati qui come Xxx) per identificare in modo univoco la sezione. Le prime quattro lettere del nome della sezione (ovvero "PAGE") devono essere maiuscole. RoutineName identifica un punto di ingresso da includere nella sezione paginabile.

Il nome più breve valido per una sezione codici paginabile in un file driver è semplicemente PAGE. Ad esempio, la direttiva pragma nell'esempio di codice seguente identifica RdrCreateConnection come punto di ingresso in una sezione codici paginabile denominata PAGE.

#ifdef  ALLOC_PRAGMA 
#pragma alloc_text(PAGE, RdrCreateConnection) 
#endif 

Per rendere il codice del driver impaginabile residente e bloccato in memoria, un driver chiama MmLockPagableCodeSection, passando un indirizzo (in genere il punto di ingresso di una routine driver) che si trova nella sezione codice paginabile. I blocchi MmLockPagableCodeSection nell'intero contenuto della sezione che contiene la routine a cui si fa riferimento nella chiamata. In altre parole, questa chiamata effettua ogni routine associata allo stesso identificatore PAGEXxx residente e bloccato in memoria.

MmLockPagableCodeSection restituisce un handle da usare durante lo sblocco della sezione (chiamando la routine MmUnlockPagableImageSection ) o quando il driver deve bloccare la sezione da posizioni aggiuntive nel codice.

Un driver può anche trattare i dati usati raramente come paginabili in modo che sia anche possibile visualizzare la pagina fino a quando il dispositivo supportato non è attivo. Ad esempio, il driver del mixer di sistema usa dati paginabili. Il dispositivo mixer non ha alcun I/O asincrono associato a esso, quindi questo driver può rendere i dati paginabili.

Il nome di una sezione dati paginabile deve iniziare con le quattro lettere "PAGE" e può essere seguito da fino a quattro caratteri per identificare in modo univoco la sezione. Le prime quattro lettere del nome della sezione (ovvero "PAGE") devono essere maiuscole.

Evitare di assegnare nomi identici alle sezioni di codice e dati. Per rendere il codice sorgente più leggibile, gli sviluppatori di driver in genere assegnano il nome PAGE alla sezione codici paginabile perché questo nome è breve e potrebbe essere visualizzato in numerose direttive pragma alloc_text. I nomi più lunghi vengono quindi assegnati a qualsiasi sezione dati paginabile(ad esempio PAGEDATA per data_seg, PAGEBSS per bss_seg e così via) che il driver potrebbe richiedere.

Ad esempio, le prime due direttive pragma nell'esempio di codice seguente definiscono due sezioni di dati paginabili, PAGEDATA e PAGEBSS. PAGEDATA viene dichiarato usando la direttiva pragma data_seg e contiene dati inizializzati. PAGEBSS viene dichiarato usando la direttiva pragma bss_seg e contiene dati non inizializzati.

#pragma data_seg("PAGEDATA")
#pragma bss_seg("PAGEBSS")

INT Variable1 = 1;
INT Variable2;

CHAR Array1[64*1024] = { 0 };
CHAR Array2[64*1024];

#pragma data_seg()
#pragma bss_seg()

In questo esempio Variable1 di codice e Array1 vengono inizializzati in modo esplicito e vengono quindi inseriti nella sezione PAGEDATA. Variable2 e vengono inizializzati in modo implicito e Array2 vengono inseriti nella sezione PAGEBSS.

Inizializzare in modo implicito le variabili globali in zero riduce le dimensioni del file eseguibile su disco e è preferibile rispetto all'inizializzazione esplicita a zero. È consigliabile evitare l'inizializzazione zero esplicita, ad eccezione dei casi in cui è necessario inserire una variabile in una sezione dati specifica.

Per creare una sezione dati residente nella memoria e bloccarla in memoria, un driver chiama MmLockPagableDataSection, passando un elemento di dati visualizzato nella sezione dati impaginabile. MmLockPagableDataSection restituisce un handle da usare nelle richieste di blocco o sblocco successive.

Per ripristinare lo stato paginabile di una sezione bloccata, chiamare MmUnlockPagableImageSection, passando il valore di handle restituito da MmLockPagableCodeSection o MmLockPagableDataSection, in base alle esigenze. La routine di scaricamento di un driver deve chiamare MmUnlockPagableImageSection per rilasciare ogni handle ottenuto per le sezioni di codice e dati bloccabili.

Il blocco di una sezione è un'operazione costosa perché gestione memoria deve cercare l'elenco dei moduli caricati prima di bloccare le pagine in memoria. Se un driver blocca una sezione da molte posizioni nel codice, deve usare mmLockPagableSectionByHandle dopo la chiamata iniziale a MmLockPagableXxx.

L'handle passato a MmLockPagableSectionByHandle è l'handle restituito dalla chiamata precedente a MmLockPagableCodeSection o MmLockPagableDataSection.

Gestione memoria gestisce un conteggio per ogni handle di sezione e incrementa questo conteggio ogni volta che un driver chiama MmLockPagableXxx per tale sezione. Una chiamata a MmUnlockPagableImageSection decrementa il conteggio. Mentre il contatore per qualsiasi handle di sezione è diverso da zero, tale sezione rimane bloccata in memoria.

L'handle di una sezione è valido fino a quando viene caricato il driver. Pertanto, un driver deve chiamare MmLockPagableXxxSezione una sola volta. Se il driver richiede chiamate di blocco aggiuntive, deve usare MmLockPagableSectionByHandle.

Se un driver chiama una routine MmLockPagableXxx per una sezione già bloccata, la gestione memoria incrementa il conteggio dei riferimenti per la sezione. Se la sezione viene paginata quando viene chiamata la routine di blocco, le pagine di Gestione memoria nella sezione e imposta il numero di riferimenti su uno.

L'uso di questa tecnica riduce al minimo l'effetto del driver sulle risorse di sistema. Quando viene eseguito il driver, può bloccare in memoria il codice e i dati che devono essere residenti. Quando non sono presenti richieste di I/O in sospeso per il dispositivo, ovvero quando il dispositivo è chiuso o se il dispositivo non è mai stato aperto, il driver può sbloccare lo stesso codice o i dati, rendendolo disponibile per essere visualizzati.

Tuttavia, dopo che un driver ha interrotto la connessione, qualsiasi codice driver che può essere chiamato durante l'elaborazione degli interruzioni deve essere sempre residente nella memoria. Anche se alcuni driver di dispositivo possono essere resi paginabili o bloccati in memoria su richiesta, alcuni set di base di codice e dati di tale driver devono essere permanentemente residenti nello spazio di sistema.

Prendere in considerazione le linee guida di implementazione seguenti per bloccare un codice o una sezione dati.

  • L'uso principale delle routine Mm(Un)LockXxx consiste nell'abilitare codice o dati normalmente non impaginati e inseriti come codice o dati non impaginati. I driver come il driver seriale e il driver parallelo sono esempi validi: se non sono presenti handle aperti a un dispositivo di questo tipo, le parti del codice non sono necessarie e possono rimanere in pagina. Il reindirizzamento e il server sono anche esempi validi di driver che possono usare questa tecnica. Quando non sono presenti connessioni attive, entrambi questi componenti possono essere visualizzati in pagina.

  • L'intera sezione paginabile è bloccata in memoria.

  • Una sezione per il codice e una per ogni driver è efficiente. Molte sezioni denominate, pageable sono in genere inefficienti.

  • Mantenere le sezioni puramente paginabili e le sezioni bloccate ma separate da sezioni bloccate su richiesta.

  • Tenere presente che MmLockPagableCodeSection e MmLockPagableDataSection non devono essere chiamati di frequente. Queste routine possono causare attività di I/O pesanti quando la gestione memoria carica la sezione. Se un driver deve bloccare una sezione da diverse posizioni nel codice, deve usare MmLockPagableSectionByHandle.