[PATCH] Locks between peb lock and window lock

Gerard Patel gerard.patel at nerim.net
Fri Nov 30 04:18:00 CST 2001


As it's the first time that I deal with locking problems, I'll be a bit
heavy-handed
in my description of the patch.

The problem has appeared with Webferret - that's a freebie application by Zdnet,
a web search engine application. It does not matter, what matters is that it is
a very heavily multi-thread application. When I ask for the app to display its
options, it actually spins a new thread to display the dialog box. When the user
ask to close the dialog box and the thread gets control again, it just does an
ExitThread, leaving to the system the care of cleaning resources.

What happens then is (as I understand it) :

- while Wine is cleaning the app's resources, in WIN_DestroyThreadWindows,
the peb lock is held, because this code is called from the User32 dll unloading
routine. In WIN_DestroyThreadWindows, windows locks are frequently used for
each window deletion.

- at the same time, when the windows of the separate thread are destroyed,
they expose windows of the main thread. These windows are repainted, and
in the process, the main thread asks for the peb lock while it is already
holding
the window lock. It has been somewhat difficult to track how and when, since
these problems seem to disappear when one adds traces to the code, the more
so when the traces are near the cause of the problem :-). I have found that
graphic driver loading and unloading is causing the peb lock to be taken

err:ntdll:RtlpWaitForCriticalSection section 0x40101b28 "rtl.c: peb_lock"
wait timed out, retrying (60 sec) fs=008f
err:ntdll:RtlpWaitForCriticalSection section 0x4076c0d8 "user.c:
USER_SysLevel" wait timed out, retrying (60 sec) fs=039f

So it seems that it's not really a good thing to call the following routines
while
the window lock is taken : CreateDC, DeleteDC, CreateCompatibleDC.
The attached patch changes Wine code to avoid a few of these situations.
I'm aware that there are other cases when the same thing happens, but the
changes seem enough to fix my problem, and I have many other crashes
to handle :-/

About why this problem happens now (it's a regression, actually), my
interpretation is that with the server being more and more called in Wine code,
costing a context switch for each server call, the probability for locking
problems
goes up.


ChangeLog:

	* window/nonclient.c, painting.c
               Remove some possible interlocking problems with peb lock


-------------- next part --------------
Index: windows/nonclient.c
===================================================================
RCS file: /home/wine/wine/windows/nonclient.c,v
retrieving revision 1.88
diff -u -r1.88 nonclient.c
--- windows/nonclient.c	2001/10/16 21:52:26	1.88
+++ windows/nonclient.c	2001/11/30 07:08:45
@@ -1393,27 +1393,40 @@
  *
  * Paint the non-client area. clip is currently unused.
  */
-static void NC_DoNCPaint( WND* wndPtr, HRGN clip, BOOL suppress_menupaint )
+static void NC_DoNCPaint( HWND hwnd, HRGN clip, BOOL suppress_menupaint )
 {
     HDC hdc;
     RECT rect;
     BOOL active;
-    HWND hwnd = wndPtr->hwndSelf;
+    WND *wndPtr;
+    DWORD dwStyle, dwExStyle;
+    WORD flags;
+    RECT rectClient, rectWindow;
+    int has_menu;
+
+    if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
+    has_menu = HAS_MENU(wndPtr);
+    dwStyle = wndPtr->dwStyle;
+    dwExStyle = wndPtr->dwExStyle;    
+    flags = wndPtr->flags;
+    rectClient = wndPtr->rectClient;
+    rectWindow = wndPtr->rectWindow;
+    WIN_ReleasePtr( wndPtr );
 
-    if ( wndPtr->dwStyle & WS_MINIMIZE ||
+    if ( dwStyle & WS_MINIMIZE ||
          !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
 
-    active  = wndPtr->flags & WIN_NCACTIVATED;
+    active  = flags & WIN_NCACTIVATED;
 
     TRACE("%04x %d\n", hwnd, active );
 
     if (!(hdc = GetDCEx( hwnd, (clip > 1) ? clip : 0, DCX_USESTYLE | DCX_WINDOW |
 			      ((clip > 1) ? (DCX_INTERSECTRGN | DCX_KEEPCLIPRGN): 0) ))) return;
 
-    if (ExcludeVisRect16( hdc, wndPtr->rectClient.left-wndPtr->rectWindow.left,
-		        wndPtr->rectClient.top-wndPtr->rectWindow.top,
-		        wndPtr->rectClient.right-wndPtr->rectWindow.left,
-		        wndPtr->rectClient.bottom-wndPtr->rectWindow.top )
+    if (ExcludeVisRect16( hdc, rectClient.left-rectWindow.left,
+		        rectClient.top-rectWindow.top,
+		        rectClient.right-rectWindow.left,
+		        rectClient.bottom-rectWindow.top )
 	== NULLREGION)
     {
 	ReleaseDC( hwnd, hdc );
@@ -1421,32 +1434,32 @@
     }
 
     rect.top = rect.left = 0;
-    rect.right  = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
-    rect.bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
+    rect.right  = rectWindow.right - rectWindow.left;
+    rect.bottom = rectWindow.bottom - rectWindow.top;
 
     SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
 
-    if (HAS_ANYFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
+    if (HAS_ANYFRAME( dwStyle, dwExStyle ))
     {
         SelectObject( hdc, GetStockObject(NULL_BRUSH) );
         Rectangle( hdc, 0, 0, rect.right, rect.bottom );
         InflateRect( &rect, -1, -1 );
     }
 
-    if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
+    if (HAS_THICKFRAME( dwStyle, dwExStyle ))
         NC_DrawFrame(hdc, &rect, FALSE, active );
-    else if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
+    else if (HAS_DLGFRAME( dwStyle, dwExStyle ))
         NC_DrawFrame( hdc, &rect, TRUE, active );
 
-    if ((wndPtr->dwStyle & WS_CAPTION) == WS_CAPTION)
+    if ((dwStyle & WS_CAPTION) == WS_CAPTION)
     {
         RECT r = rect;
         r.bottom = rect.top + GetSystemMetrics(SM_CYSIZE);
         rect.top += GetSystemMetrics(SM_CYSIZE) + GetSystemMetrics(SM_CYBORDER);
-        NC_DrawCaption( hdc, &r, hwnd, wndPtr->dwStyle, active );
+        NC_DrawCaption( hdc, &r, hwnd, dwStyle, active );
     }
 
-    if (HAS_MENU(wndPtr))
+    if (has_menu)
     {
 	RECT r = rect;
 	r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);  /* default height */
@@ -1455,14 +1468,14 @@
 
       /* Draw the scroll-bars */
 
-    if (wndPtr->dwStyle & WS_VSCROLL)
+    if (dwStyle & WS_VSCROLL)
         SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
-    if (wndPtr->dwStyle & WS_HSCROLL)
+    if (dwStyle & WS_HSCROLL)
         SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
 
       /* Draw the "size-box" */
 
-    if ((wndPtr->dwStyle & WS_VSCROLL) && (wndPtr->dwStyle & WS_HSCROLL))
+    if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
     {
         RECT r = rect;
         r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
@@ -1481,7 +1494,7 @@
 /******************************************************************************
  *
  *   void  NC_DoNCPaint95(
- *      WND  *wndPtr,
+ *      HWND  hwnd,
  *      HRGN  clip,
  *      BOOL  suppress_menupaint )
  *
@@ -1503,19 +1516,32 @@
  *****************************************************************************/
 
 static void  NC_DoNCPaint95(
-    WND  *wndPtr,
+    HWND  hwnd,
     HRGN  clip,
     BOOL  suppress_menupaint )
 {
     HDC hdc;
     RECT rfuzz, rect, rectClip;
     BOOL active;
-    HWND hwnd = wndPtr->hwndSelf;
+    WND *wndPtr;
+    DWORD dwStyle, dwExStyle;
+    WORD flags;
+    RECT rectClient, rectWindow;
+    int has_menu;
+
+    if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
+    has_menu = HAS_MENU(wndPtr);
+    dwStyle = wndPtr->dwStyle;
+    dwExStyle = wndPtr->dwExStyle;    
+    flags = wndPtr->flags;
+    rectClient = wndPtr->rectClient;
+    rectWindow = wndPtr->rectWindow;
+    WIN_ReleasePtr( wndPtr );
 
-    if ( wndPtr->dwStyle & WS_MINIMIZE ||
+    if ( dwStyle & WS_MINIMIZE ||
          !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
 
-    active  = wndPtr->flags & WIN_NCACTIVATED;
+    active  = flags & WIN_NCACTIVATED;
 
     TRACE("%04x %d\n", hwnd, active );
 
@@ -1530,10 +1556,10 @@
 			      ((clip > 1) ?(DCX_INTERSECTRGN | DCX_KEEPCLIPRGN) : 0) ))) return;
 
 
-    if (ExcludeVisRect16( hdc, wndPtr->rectClient.left-wndPtr->rectWindow.left,
-		        wndPtr->rectClient.top-wndPtr->rectWindow.top,
-		        wndPtr->rectClient.right-wndPtr->rectWindow.left,
-		        wndPtr->rectClient.bottom-wndPtr->rectWindow.top )
+    if (ExcludeVisRect16( hdc, rectClient.left-rectWindow.left,
+		        rectClient.top-rectWindow.top,
+		        rectClient.right-rectWindow.left,
+		        rectClient.bottom-rectWindow.top )
 	== NULLREGION)
     {
 	ReleaseDC( hwnd, hdc );
@@ -1541,8 +1567,8 @@
     }
 
     rect.top = rect.left = 0;
-    rect.right  = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
-    rect.bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
+    rect.right  = rectWindow.right - rectWindow.left;
+    rect.bottom = rectWindow.bottom - rectWindow.top;
 
     if( clip > 1 )
 	GetRgnBox( clip, &rectClip );
@@ -1554,19 +1580,19 @@
 
     SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
 
-    if (HAS_STATICOUTERFRAME(wndPtr->dwStyle, wndPtr->dwExStyle)) {
+    if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
         DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
     }
-    else if (HAS_BIGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle)) {
+    else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
         DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
     }
 
-    NC_DrawFrame95(hdc, &rect, active, wndPtr->dwStyle, wndPtr->dwExStyle );
+    NC_DrawFrame95(hdc, &rect, active, dwStyle, dwExStyle );
 
-    if ((wndPtr->dwStyle & WS_CAPTION) == WS_CAPTION)
+    if ((dwStyle & WS_CAPTION) == WS_CAPTION)
     {
         RECT  r = rect;
-        if (wndPtr->dwExStyle & WS_EX_TOOLWINDOW) {
+        if (dwExStyle & WS_EX_TOOLWINDOW) {
             r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
             rect.top += GetSystemMetrics(SM_CYSMCAPTION);
         }
@@ -1575,11 +1601,11 @@
             rect.top += GetSystemMetrics(SM_CYCAPTION);
         }
         if( !clip || IntersectRect( &rfuzz, &r, &rectClip ) )
-            NC_DrawCaption95 (hdc, &r, hwnd, wndPtr->dwStyle,
-                              wndPtr->dwExStyle, active);
+            NC_DrawCaption95 (hdc, &r, hwnd, dwStyle,
+                              dwExStyle, active);
     }
 
-    if (HAS_MENU(wndPtr))
+    if (has_menu)
     {
 	RECT r = rect;
 	r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
@@ -1593,18 +1619,18 @@
     TRACE("After MenuBar, rect is (%d, %d)-(%d, %d).\n",
           rect.left, rect.top, rect.right, rect.bottom );
 
-    if (wndPtr->dwExStyle & WS_EX_CLIENTEDGE)
+    if (dwExStyle & WS_EX_CLIENTEDGE)
 	DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
 
     /* Draw the scroll-bars */
 
-    if (wndPtr->dwStyle & WS_VSCROLL)
+    if (dwStyle & WS_VSCROLL)
         SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
-    if (wndPtr->dwStyle & WS_HSCROLL)
+    if (dwStyle & WS_HSCROLL)
         SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
 
     /* Draw the "size-box" */
-    if ((wndPtr->dwStyle & WS_VSCROLL) && (wndPtr->dwStyle & WS_HSCROLL))
+    if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
     {
         RECT r = rect;
         r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
@@ -1626,17 +1652,20 @@
 LONG NC_HandleNCPaint( HWND hwnd , HRGN clip)
 {
     WND* wndPtr = WIN_FindWndPtr( hwnd );
+    DWORD dwStyle;
+    if (!wndPtr) return 0;
+    dwStyle = wndPtr->dwStyle;
+    WIN_ReleaseWndPtr(wndPtr);
 
-    if( wndPtr && wndPtr->dwStyle & WS_VISIBLE )
+    if( dwStyle & WS_VISIBLE )
     {
-	if( wndPtr->dwStyle & WS_MINIMIZE )
+	if( dwStyle & WS_MINIMIZE )
 	    WINPOS_RedrawIconTitle( hwnd );
 	else if (TWEAK_WineLook == WIN31_LOOK)
-	    NC_DoNCPaint( wndPtr, clip, FALSE );
+	    NC_DoNCPaint( hwnd, clip, FALSE );
 	else
-	    NC_DoNCPaint95( wndPtr, clip, FALSE );
+	    NC_DoNCPaint95( hwnd, clip, FALSE );
     }
-    WIN_ReleaseWndPtr(wndPtr);
     return 0;
 }
 
@@ -1659,13 +1688,13 @@
     {
 	if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
 	else wndPtr->flags &= ~WIN_NCACTIVATED;
+        WIN_ReleaseWndPtr(wndPtr);
 
 	if (IsIconic(hwnd)) WINPOS_RedrawIconTitle( hwnd );
 	else if (TWEAK_WineLook == WIN31_LOOK)
-	    NC_DoNCPaint( wndPtr, (HRGN)1, FALSE );
+	    NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
 	else
-	    NC_DoNCPaint95( wndPtr, (HRGN)1, FALSE );
-        WIN_ReleaseWndPtr(wndPtr);
+	    NC_DoNCPaint95( hwnd, (HRGN)1, FALSE );
     }
     return TRUE;
 }
Index: windows/painting.c
===================================================================
RCS file: /home/wine/wine/windows/painting.c,v
retrieving revision 1.62
diff -u -r1.62 painting.c
--- windows/painting.c	2001/11/13 22:23:49	1.62
+++ windows/painting.c	2001/11/30 07:08:45
@@ -341,6 +341,8 @@
     wndPtr->hrgnUpdate = 0;
     wndPtr->flags &= ~WIN_INTERNAL_PAINT;
 
+    WIN_ReleaseWndPtr(wndPtr);
+
     HideCaret( hwnd );
 
     TRACE("hrgnUpdate = %04x, \n", hrgnUpdate);
@@ -368,7 +370,6 @@
     if (!lps->hdc)
     {
         WARN("GetDCEx() failed in BeginPaint(), hwnd=%04x\n", hwnd);
-        WIN_ReleaseWndPtr(wndPtr);
         return 0;
     }
 
@@ -388,6 +389,7 @@
     TRACE("box = (%i,%i - %i,%i)\n", lps->rcPaint.left, lps->rcPaint.top,
 		    lps->rcPaint.right, lps->rcPaint.bottom );
 
+    if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
     if (wndPtr->flags & WIN_NEEDS_ERASEBKGND)
     {
         wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
-------------- next part --------------



More information about the wine-patches mailing list