On Thu, Apr 14, 2005 at 03:05:36PM +0200, Alexandre Julliard wrote:
Actually it should be possible to handle the fault using a vectored handler, without requiring internal functions at all.
Completely untested (what do people use to test DIB handling?), but it compiles. Is something like this what you had it mind?
Index: dlls/ntdll/ntdll.spec =================================================================== RCS file: /var/cvs/wine/dlls/ntdll/ntdll.spec,v retrieving revision 1.175 diff -u -p -r1.175 ntdll.spec --- dlls/ntdll/ntdll.spec 30 Mar 2005 10:22:51 -0000 1.175 +++ dlls/ntdll/ntdll.spec 17 Apr 2005 04:18:44 -0000 @@ -1035,4 +1035,3 @@ @ cdecl MODULE_DllThreadAttach(ptr) @ cdecl MODULE_GetLoadOrderW(ptr wstr wstr) @ cdecl VERSION_Init(wstr) -@ cdecl VIRTUAL_SetFaultHandler(ptr ptr ptr) Index: dlls/ntdll/virtual.c =================================================================== RCS file: /var/cvs/wine/dlls/ntdll/virtual.c,v retrieving revision 1.46 diff -u -p -r1.46 virtual.c --- dlls/ntdll/virtual.c 22 Feb 2005 19:33:50 -0000 1.46 +++ dlls/ntdll/virtual.c 17 Apr 2005 04:20:14 -0000 @@ -212,11 +212,14 @@ void VIRTUAL_Dump(void) * * Find the view containing a given address. The csVirtual section must be held by caller. * + * PARAMS + * addr [I] Address + * * RETURNS * View: Success * NULL: Failure */ -static struct file_view *VIRTUAL_FindView( const void *addr ) /* [in] Address */ +static struct file_view *VIRTUAL_FindView( const void *addr ) { struct list *ptr;
@@ -473,10 +476,13 @@ static void VIRTUAL_GetWin32Prot( * * Build page protections from Win32 flags. * + * PARAMS + * protect [I] Win32 protection flags + * * RETURNS * Value of page protection flags */ -static BYTE VIRTUAL_GetProt( DWORD protect ) /* [in] Win32 protection flags */ +static BYTE VIRTUAL_GetProt( DWORD protect ) { BYTE vprot;
@@ -1098,25 +1104,6 @@ void virtual_init(void)
/*********************************************************************** - * VIRTUAL_SetFaultHandler - */ -BOOL VIRTUAL_SetFaultHandler( LPCVOID addr, HANDLERPROC proc, LPVOID arg ) -{ - FILE_VIEW *view; - BOOL ret = FALSE; - - RtlEnterCriticalSection( &csVirtual ); - if ((view = VIRTUAL_FindView( addr ))) - { - view->handlerProc = proc; - view->handlerArg = arg; - ret = TRUE; - } - RtlLeaveCriticalSection( &csVirtual ); - return ret; -} - -/*********************************************************************** * VIRTUAL_HandleFault */ DWORD VIRTUAL_HandleFault( LPCVOID addr ) Index: dlls/x11drv/dib.c =================================================================== RCS file: /var/cvs/wine/dlls/x11drv/dib.c,v retrieving revision 1.35 diff -u -p -r1.35 dib.c --- dlls/x11drv/dib.c 14 Apr 2005 12:48:31 -0000 1.35 +++ dlls/x11drv/dib.c 17 Apr 2005 03:54:45 -0000 @@ -38,11 +38,32 @@ #include "winbase.h" #include "wingdi.h" #include "x11drv.h" +#include "excpt.h" +#include "wine/list.h" #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(bitmap); WINE_DECLARE_DEBUG_CHANNEL(x11drv);
+struct mem_area +{ + struct list entry; /* Entry in global mem area list */ + const void *base; /* Base address */ + UINT size; /* Size in bytes */ + void *data; /* Data associated with this area */ +}; + +static struct list mem_areas_list = LIST_INIT(mem_areas_list); + +static CRITICAL_SECTION csMemAreas; +static CRITICAL_SECTION_DEBUG csMemAreas_debug = +{ + 0, 0, &csMemAreas, + { &csMemAreas_debug.ProcessLocksList, &csMemAreas_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": csMemAreas") } +}; +static CRITICAL_SECTION csMemAreas = { &csMemAreas_debug, -1, 0, 0, 0, 0 }; + static int ximageDepthTable[32];
/* This structure holds the arguments for DIB_SetImageBits() */ @@ -88,6 +109,89 @@ static INT X11DRV_DIB_Coerce(X_PHYSBITMA static INT X11DRV_DIB_Lock(X_PHYSBITMAP *,INT,BOOL); static void X11DRV_DIB_Unlock(X_PHYSBITMAP *,BOOL);
+/*********************************************************************** + * mem_area_find + * + * Find the memory area containing a given address. + * The csMemAreas section must be held by caller. + * + * PARAMS + * addr [I] Address + * + * RETURNS + * Success: area + * Failure: NULL + */ +static struct mem_area *mem_area_find( const void *addr ) +{ + struct list *ptr; + + LIST_FOR_EACH( ptr, &mem_areas_list ) + { + struct mem_area *area = LIST_ENTRY( ptr, struct mem_area, entry ); + if (area->base > addr) break; + if ((const char*)addr < (const char*)area->base + area->size) return area; + } + return NULL; +} + +/*********************************************************************** + * mem_area_add + * + * Adds a memory area to the list. + * + * PARAMS + * base [I] Beginning address of the area + * size [I] Size of the area + * data [I] Data associated with the area + * + */ +static struct mem_area *mem_area_add( const void *base, UINT size, void *data ) +{ + struct mem_area *area; + + EnterCriticalSection( &csMemAreas ); + + area = HeapAlloc(GetProcessHeap(), 0, sizeof(*area)); + if (area) + { + area->base = base; + area->size = size; + area->data = data; + list_add_head( &mem_areas_list, &area->entry ); + } + + LeaveCriticalSection( &csMemAreas ); + + return area; +} + + +/*********************************************************************** + * mem_area_del + * + * Removes a memory area from the list. + * + * PARAMS + * addr [I] Address + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +static BOOL mem_area_del( const void *addr ) +{ + struct mem_area *area; + + EnterCriticalSection( &csMemAreas ); + area = mem_area_find( addr ); + if (area) list_remove( &area->entry ); + LeaveCriticalSection( &csMemAreas ); + + return area != NULL; +} + + /* Some of the following helper functions are duplicated in dlls/gdi/dib.c @@ -4268,22 +4372,34 @@ static void X11DRV_DIB_DoUpdateDIBSectio /*********************************************************************** * X11DRV_DIB_FaultHandler */ -static BOOL X11DRV_DIB_FaultHandler( LPVOID res, LPCVOID addr ) +LONG CALLBACK X11DRV_DIB_FaultHandler( PEXCEPTION_POINTERS ep ) { - X_PHYSBITMAP *physBitmap = res; - INT state = X11DRV_DIB_Lock( physBitmap, DIB_Status_None, FALSE ); + struct mem_area *area; + X_PHYSBITMAP *physBitmap; + INT state;
- if (state != DIB_Status_InSync) { - /* no way to tell whether app needs read or write yet, - * try read first */ - X11DRV_DIB_Coerce( physBitmap, DIB_Status_InSync, FALSE ); - } else { - /* hm, apparently the app must have write access */ - X11DRV_DIB_Coerce( physBitmap, DIB_Status_AppMod, FALSE ); - } - X11DRV_DIB_Unlock( physBitmap, TRUE ); + if (ep->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION) + return EXCEPTION_CONTINUE_SEARCH;
- return TRUE; + EnterCriticalSection(&csMemAreas); + area = mem_area_find(ep->ExceptionRecord->ExceptionAddress); + if (area) physBitmap = (X_PHYSBITMAP *)area->data; + else physBitmap = NULL; + LeaveCriticalSection(&csMemAreas); + + if (!physBitmap) return EXCEPTION_CONTINUE_SEARCH; + + state = X11DRV_DIB_Lock( physBitmap, DIB_Status_None, FALSE ); + if (state != DIB_Status_InSync) { + /* no way to tell whether app needs read or write yet, try read first */ + X11DRV_DIB_Coerce( physBitmap, DIB_Status_InSync, FALSE ); + } else { + /* hm, apparently the app must have write access */ + X11DRV_DIB_Coerce( physBitmap, DIB_Status_AppMod, FALSE ); + } + X11DRV_DIB_Unlock( physBitmap, TRUE ); + + return EXCEPTION_CONTINUE_EXECUTION; }
/*********************************************************************** @@ -4566,7 +4682,6 @@ static XImage *X11DRV_XShmCreateImage( i HBITMAP X11DRV_CreateDIBSection( X11DRV_PDEVICE *physDev, HBITMAP hbitmap, const BITMAPINFO *bmi, UINT usage ) { - extern BOOL VIRTUAL_SetFaultHandler(LPCVOID addr, BOOL (*proc)(LPVOID, LPCVOID), LPVOID arg); X_PHYSBITMAP *physBitmap; DIBSECTION dib;
@@ -4602,7 +4717,7 @@ HBITMAP X11DRV_CreateDIBSection( X11DRV_
/* install fault handler */ InitializeCriticalSection( &physBitmap->lock ); - if (VIRTUAL_SetFaultHandler(dib.dsBm.bmBits, X11DRV_DIB_FaultHandler, physBitmap)) + if (mem_area_add(dib.dsBm.bmBits, dib.dsBmih.biSize, physBitmap)) { X11DRV_DIB_DoProtectDIBSection( physBitmap, PAGE_READWRITE ); physBitmap->status = DIB_Status_AppMod; @@ -4616,6 +4731,8 @@ HBITMAP X11DRV_CreateDIBSection( X11DRV_ */ void X11DRV_DIB_DeleteDIBSection(X_PHYSBITMAP *physBitmap, DIBSECTION *dib) { + mem_area_del(dib->dsBm.bmBits); + if (dib->dshSection) X11DRV_DIB_Coerce(physBitmap, DIB_Status_InSync, FALSE);
Index: dlls/x11drv/x11drv.h =================================================================== RCS file: /var/cvs/wine/dlls/x11drv/x11drv.h,v retrieving revision 1.69 diff -u -p -r1.69 x11drv.h --- dlls/x11drv/x11drv.h 14 Apr 2005 12:48:11 -0000 1.69 +++ dlls/x11drv/x11drv.h 17 Apr 2005 03:42:32 -0000 @@ -234,6 +234,7 @@ extern BOOL X11DRV_SwapBuffers(X11DRV_PD extern void X11DRV_BITMAP_Init(void); extern void X11DRV_FONT_Init( int log_pixels_x, int log_pixels_y );
+extern LONG CALLBACK X11DRV_DIB_FaultHandler( PEXCEPTION_POINTERS ep ); extern int X11DRV_DIB_BitmapInfoSize( const BITMAPINFO * info, WORD coloruse ); extern XImage *X11DRV_DIB_CreateXImage( int width, int height, int depth ); extern HGLOBAL X11DRV_DIB_CreateDIBFromBitmap(HDC hdc, HBITMAP hBmp); Index: dlls/x11drv/x11drv_main.c =================================================================== RCS file: /var/cvs/wine/dlls/x11drv/x11drv_main.c,v retrieving revision 1.102 diff -u -p -r1.102 x11drv_main.c --- dlls/x11drv/x11drv_main.c 14 Apr 2005 12:48:11 -0000 1.102 +++ dlls/x11drv/x11drv_main.c 16 Apr 2005 16:59:03 -0000 @@ -362,6 +362,9 @@ static BOOL process_attach(void) using_wine_desktop = 1; }
+ /* initialize DIB handling */ + AddVectoredExceptionHandler( TRUE, X11DRV_DIB_FaultHandler ); + /* initialize GDI */ X11DRV_GDI_Initialize( display );
@@ -422,6 +425,9 @@ static void process_detach(void) /* cleanup GDI */ X11DRV_GDI_Finalize();
+ /* cleanup DIB handling */ + RemoveVectoredExceptionHandler( X11DRV_DIB_FaultHandler ); + DeleteCriticalSection( &X11DRV_CritSection ); }