Am 09.06.2022 um 13:18 schrieb Bonita Montero:
> mmap() hat den Nachteil, dass es recht aufwendig werden kann, I/O-Fehler
> abzufangen. Unter Windows ist das alles mit Structured Exception Hand-
> ling (ähnlich wie rudimetäre C++-Exceptions, geht aber auch in C) so
> simpel wie eine Exception in Java abzufangen, unter Unix wirds mega
> -frickelig weil der Code durch den Signal -Handler seinen gewohnten
> Pfad verlsssen muss.
Ich hab das mal Windows-mäßig in C++20 nachprogrammiert und
geschaut, ob sowas wie ein I/O-Error auf einem memory-mapped
File wirklich abzufangen ist.
#include <Windows.h>
#include <iostream>
#include <atomic>
using namespace std;
using XHANDLE = unique_ptr<void, decltype([]( void *h ) { h && h !=
INVALID_HANDLE_VALUE && CloseHandle( (HANDLE)h ); })>;
using XMAP_VIEW = unique_ptr<void, decltype([]( void *p ) { p &&
UnmapViewOfFile( p ); })>;
void readLoop( void *p, size_t n );
int wmain( int argc, wchar_t **argv )
{
if( argc < 2 )
return EXIT_FAILURE;
XHANDLE xhFile( CreateFileW( argv[1], GENERIC_READ, FILE_SHARE_READ |
FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ) );
if( xhFile.get() == INVALID_HANDLE_VALUE )
return EXIT_FAILURE;
LARGE_INTEGER liFileSize;
if( !GetFileSizeEx( xhFile.get(), &liFileSize ) || liFileSize.QuadPart
> (size_t)-1 )
return EXIT_FAILURE;
XHANDLE xhMappging( CreateFileMapping( xhFile.get(), nullptr,
PAGE_READONLY, 0, 0, nullptr ) );
if( !xhMappging.get() )
return EXIT_FAILURE;
XMAP_VIEW mapView( MapViewOfFile( xhMappging.get(), FILE_MAP_READ, 0,
0, 0 ) );
if( !mapView.get() )
return EXIT_FAILURE;
readLoop( mapView.get(), (size_t)liFileSize.QuadPart );
}
void readLoop( void *p, size_t n )
{
atomic_char
*pa = (atomic_char *)p,
*paEnd = pa + n;
__try
{
for( ; ; )
for( atomic_char *paScn = pa; paScn != paEnd; ++paScn )
(void)paScn->load( memory_order_relaxed );
}
__except( EXCEPTION_EXECUTE_HANDLER )
{
cout << "I/O error" << endl;
}
}
Ich hab das zunächst mit einem File auf einer mechanischen Platte
ausprobiert und das File während der unteren Schleife einfach gelöscht.
Das hat nicht funktioniert bzw. das File war dann zwar gelöscht, aber
die Schleife lief weiter, d.h. ich nehme mal an, dass der Kernel die
gemappten Cluster einfach noch offen lässt, während das File in den
Verwaltungsdaten des Dateisystems einfach schon weg war.
Dann habe ich das 4GB-File auf einen Stick kopiert, den raus- und
reingesteckt damit der entsprechend Cache geflusht ist, obiges Pro-
gramm drauf angesetzt und währenddessen den Stick rausgezogen; und
siehe da: ich krieg eine Access Violation und die wird auch sauber
abgefangen.
Sowas wünsche ich mir für Unix bzw. die synchronen Signale wie SIGSEGV,
SIGFPE über einen Signal-Handler zu handeln ist meiner Meinung nach
ziemlicher Murks.