Prima di tutto, vorrei dire che questo dovrebbe servire come argomento valido per non utilizzaremmap
inutilmente come "lettura ottimizzata" o simile. A parte la rimozione del dispositivo, problemi come il troncamento dei file da parte di altri processi possono causare l'accesso agli errori con SIGBUS
.
Se è davvero necessario utilizzare mmap
, è possibile installare un gestore di segnale per SIGBUS
. Il suo compito dovrebbe essere sostanzialmente a:
- impostare una (se il programma è multi-threaded o thread-local,) flag globale che un
SIGBUS
si è verificato, in modo che il codice ha provocato l'errore può essere a conoscenza.
- Chiama il
mmap
con MAP_FIXED
per mappare una nuova pagina anonima sopra alla pagina di errore. Opzionalmente riempirlo con dati che saranno riconosciuti dal codice che accede alla mappa come errati; questo potrebbe rendere superfluo il passaggio 1.
Un approccio alternativo potrebbe essere quello di impostare un globale (o thread-locale) jmp_buf
prima di accedere la mappa, e hanno il gestore di segnale semplicemente chiamare longjmp
.
Nota che né mmap
né longjmp
è async-signal-safe, ma la SIGBUS
in questione non è un segnale asincrono (anche se dovrebbe forse essere considerato uno se l'accesso ha provocato l'errore è accaduto all'interno di una libreria non async-signal-safe funzione come sscanf
). Fintanto che è il tuo codice personale, e non le funzioni di libreria, ad accedere alla mappa, dovresti essere al sicuro con entrambi. E mmap
è sicuro per il segnale asincrono nella maggior parte/tutte le implementazioni del mondo reale, quindi dovresti essere in regola con la prima soluzione in pratica anche se non è formalmente corretta.
fonte
2012-10-15 13:21:56
Non penso che sia molto utile a causa delle possibili condizioni di gara. Sarebbe utile aspettarsi e prendere 'SIGBUS' attorno al codice che accede alla regione mappata? O qualcosa di simile? –
No. 'SIGBUS' non è necessariamente recuperabile, sebbene alcune implementazioni ritentino l'istruzione di errore dopo il ritorno dal gestore. –
@SimonRichter Non è necessario riprovare l'istruzione di errore, è solo necessario determinare che non è possibile procedere con una lettura/scrittura, dopo di che si interrompe il tentativo di accedere alla regione e tornare al chiamante con qualche indicazione di errore. Forse 'setjmp()'/'longjmp()' sarebbe in grado di evitare la riesecuzione dell'istruzione di errore. –