È possibile forzare un arresto anomalo se si verifica una scrittura in una determinata posizione di memoria con una granularità inferiore a quella della pagina?

StackOverflow https://stackoverflow.com/questions/2484959

Domanda

Sto scrivendo un programma che per motivi di prestazioni utilizza la memoria condivisa (sono stati valutati socket e pipe come alternative, e non sono abbastanza veloci per il mio compito, in generale qualsiasi metodo IPC che prevede copie è troppo lento).Nella regione della memoria condivisa scrivo molte strutture di dimensione fissa.C'è un programma responsabile della scrittura delle strutture nella memoria condivisa e molti client che leggono da esso.Tuttavia, esiste un membro di ciascuna struttura su cui i client devono scrivere (un conteggio dei riferimenti, che verranno aggiornati in modo atomico).Tutti gli altri membri dovrebbero essere letti solo dai client.

Poiché i client devono modificare quell'unico membro, non possono mappare l'area di memoria condivisa come di sola lettura.Ma non dovrebbero nemmeno armeggiare con gli altri membri e poiché questi programmi sono scritti in C++, è possibile la corruzione della memoria.Idealmente, dovrebbe essere il più difficile possibile per un client mandarne in crash un altro.Sono preoccupato solo per i client difettosi, non per quelli dannosi, quindi sono consentite soluzioni imperfette.

Posso provare a impedire ai client di sovrascrivere dichiarando i membri nell'intestazione che usano come const, ma ciò non impedirà la sovrascrittura del danneggiamento della memoria (overflow del buffer, cast errati, ecc.).Posso inserire canarini, ma poi devo pagare costantemente il costo del loro controllo.

Invece di memorizzare direttamente il membro del conteggio dei riferimenti, potrei memorizzare un puntatore ai dati effettivi in ​​una pagina mappata di sola scrittura separata, mantenendo le strutture nelle pagine mappate di sola lettura.Funzionerà, il sistema operativo forzerà l'arresto anomalo della mia applicazione se provo a scrivere sui dati puntati, ma l'archiviazione indiretta può essere indesiderabile quando provo a scrivere algoritmi senza blocco, perché la necessità di seguire un altro livello di direzione indiretta può cambiare la possibilità di fare qualcosa in modo atomico.

Esiste un modo per contrassegnare aree di memoria più piccole in modo tale che scriverle faccia esplodere la tua app?Alcune piattaforme hanno watchpoint hardware, e forse potrei attivarne uno con assemblaggio in linea, ma sarei limitato a solo 4 alla volta su x86 a 32 bit e ognuno potrebbe coprire solo parte della struttura perché sono limitati a 4 byte.Renderebbe anche difficile il debug del mio programma;)

Modificare:ho trovato questo documento piuttosto strabiliante, ma sfortunatamente richiede l'utilizzo della memoria ECC e di un kernel Linux modificato.

È stato utile?

Soluzione

Non penso che sia possibile leggere solo alcuni bit in questo modo a livello del sistema operativo.

Una cosa che mi è venuta in mente proprio ora è che potresti inserire i conteggi dei riferimenti in una pagina diversa come hai suggerito.Se le strutture hanno una dimensione comune e si trovano tutte in posizioni di memoria sequenziali, è possibile utilizzare l'aritmetica del puntatore per individuare un conteggio dei riferimenti dal puntatore della struttura, anziché avere un puntatore all'interno della struttura.Questo potrebbe essere meglio che avere un puntatore per il tuo caso d'uso.

long *refCountersBase;//The start address of the ref counters page
MyStruct *structsBase;//The start address of your structures page

//get address to reference counter
long *getRefCounter(MyStruct *myStruct )
{
    size_t n = myStruct - structsBase;
    long *ref = refCountersBase + n;
    return ref;
}

Altri suggerimenti

Dovresti aggiungere un gestore di segnale per SIGSEGV che ripristini dall'eccezione, ma solo per determinati indirizzi.Un punto di partenza potrebbe essere http://www.opengroup.org/onlinepubs/009695399/basedefs/signal.h.html e la documentazione corrispondente per il tuo sistema operativo.

Modificare: Credo che ciò che vuoi sia eseguire la scrittura e il ritorno se l'indirizzo di scrittura è effettivamente OK e chiamare in coda il precedente gestore di eccezioni (il puntatore che ottieni quando installi il gestore di eccezioni) se vuoi propagare l'eccezione.Non ho esperienza però in queste cose.

Non ho mai sentito parlare di imporre la sola lettura con una granularità inferiore a una pagina, quindi potresti essere sfortunato in quella direzione a meno che tu non riesca a mettere ciascuna struttura su due pagine.Se puoi permetterti due pagine per struttura, puoi inserire il conteggio dei riferimenti su una delle pagine e rendere l'altra di sola lettura.

Potresti scrivere un'API anziché utilizzare solo le intestazioni.Forzare i client a utilizzare l'API eliminerebbe la maggior parte dei problemi di corruzione.

Mantenere i dati con il conteggio dei riferimenti anziché su una pagina diversa aiuterà con la posizione dei dati e quindi migliorerà le prestazioni della cache.

È necessario considerare che un lettore potrebbe avere un problema e non riuscire ad aggiornare correttamente il proprio conteggio dei riferimenti.Inoltre, lo scrittore potrebbe non riuscire a completare un aggiornamento.Affrontare queste cose richiede controlli aggiuntivi.Puoi combinare tali controlli con l'API.Potrebbe valere la pena sperimentare per misurare le implicazioni sulle prestazioni di qualche tipo di controllo dell'integrità.Potrebbe essere abbastanza veloce mantenere un checksum, qualcosa di semplice come adler32.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top