From 6f1b6424791a21e197dcebf3f682206b585c863c Mon Sep 17 00:00:00 2001
From: Alexandre Julliard <julliard@winehq.org>
Date: Wed, 24 Nov 1999 01:14:04 +0000
Subject: [PATCH] Raise an exception when a critical section wait failed.

---
 debugger/dbg.y          |  3 +++
 include/winbase.h       |  2 ++
 scheduler/critsection.c | 38 ++++++++++++++++++++++++--------------
 3 files changed, 29 insertions(+), 14 deletions(-)

diff --git a/debugger/dbg.y b/debugger/dbg.y
index e6f453dce45..96c6c7bb8e8 100644
--- a/debugger/dbg.y
+++ b/debugger/dbg.y
@@ -693,6 +693,9 @@ DWORD wine_debugger( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance
         case CONTROL_C_EXIT:
             fprintf( stderr, "^C" );
             break;
+        case EXCEPTION_CRITICAL_SECTION_WAIT:
+            fprintf( stderr, "critical section %08lx wait failed", rec->ExceptionInformation[0] );
+            break;
         default:
             fprintf( stderr, "%08lx", rec->ExceptionCode );
             break;
diff --git a/include/winbase.h b/include/winbase.h
index 7a21b01695c..69a656faa8f 100644
--- a/include/winbase.h
+++ b/include/winbase.h
@@ -973,6 +973,8 @@ typedef DWORD (WINAPI *LPPROGRESS_ROUTINE)(LARGE_INTEGER, LARGE_INTEGER, LARGE_I
 #define EXCEPTION_INVALID_HANDLE            STATUS_INVALID_HANDLE
 #define CONTROL_C_EXIT                      STATUS_CONTROL_C_EXIT
 
+/* Wine extension; Windows doesn't have a name for this code */
+#define EXCEPTION_CRITICAL_SECTION_WAIT     0xc0000194
 
 #define DUPLICATE_CLOSE_SOURCE		0x00000001
 #define DUPLICATE_SAME_ACCESS		0x00000002
diff --git a/scheduler/critsection.c b/scheduler/critsection.c
index 1f46cdbdc42..d6e666aa287 100644
--- a/scheduler/critsection.c
+++ b/scheduler/critsection.c
@@ -10,6 +10,7 @@
 #include <sys/types.h>
 #include "winerror.h"
 #include "winbase.h"
+#include "ntddk.h"
 #include "heap.h"
 #include "debugtools.h"
 #include "thread.h"
@@ -78,21 +79,30 @@ void WINAPI EnterCriticalSection( CRITICAL_SECTION *crit )
         }
 
         /* Now wait for it */
-        res = WaitForSingleObject( crit->LockSemaphore, 5000L );
-        if ( res == WAIT_TIMEOUT )
+        for (;;)
         {
-            ERR_(win32)("Critical section %p wait timed out, retrying (60 sec)\n", crit );
-            res = WaitForSingleObject( crit->LockSemaphore, 60000L );
-        }
-        if ( res == WAIT_TIMEOUT && TRACE_ON(relay) )
-        {
-            ERR_(win32)("Critical section %p wait timed out, retrying (5 min)\n", crit );
-            res = WaitForSingleObject( crit->LockSemaphore, 300000L );
-        }
-        if (res != STATUS_WAIT_0)
-        {
-            ERR_(win32)("Critical section %p wait failed err=%lx\n", crit, res );
-            /* FIXME: should raise an exception */
+            EXCEPTION_RECORD rec;
+
+            res = WaitForSingleObject( crit->LockSemaphore, 5000L );
+            if ( res == WAIT_TIMEOUT )
+            {
+                ERR_(win32)("Critical section %p wait timed out, retrying (60 sec)\n", crit );
+                res = WaitForSingleObject( crit->LockSemaphore, 60000L );
+                if ( res == WAIT_TIMEOUT && TRACE_ON(relay) )
+                {
+                    ERR_(win32)("Critical section %p wait timed out, retrying (5 min)\n", crit );
+                    res = WaitForSingleObject( crit->LockSemaphore, 300000L );
+                }
+            }
+            if (res == STATUS_WAIT_0) break;
+
+            rec.ExceptionCode    = EXCEPTION_CRITICAL_SECTION_WAIT;
+            rec.ExceptionFlags   = 0;
+            rec.ExceptionRecord  = NULL;
+            rec.ExceptionAddress = RtlRaiseException;  /* sic */
+            rec.NumberParameters = 1;
+            rec.ExceptionInformation[0] = (DWORD)crit;
+            RtlRaiseException( &rec );
         }
     }
     crit->OwningThread   = GetCurrentThreadId();
-- 
GitLab