[0.4.12][UMPNPMGR][USETUP] Fix the way device-install events are queued and dequeued...
authorJoachim Henze <Joachim.Henze@reactos.org>
Fri, 15 Jan 2021 02:27:01 +0000 (03:27 +0100)
committerJoachim Henze <Joachim.Henze@reactos.org>
Fri, 15 Jan 2021 02:27:01 +0000 (03:27 +0100)
CORE-16103 "Network adapters sporadically fail to install with Code31 CM_PROB_FAILED_ADD"

This first and foremost reverts the guilty rev 0.4.12-dev-72-g 043a98ddd9969ceebf50682e296565dc11f25fc0
by porting back the fix 0.4.15-dev-1074-g ffc96d26ec297a6f9feec7c1e526efefa08809e0
the fix had to be adopted a bit for releases/0.4.12 due to some unrelated refactoring in umpnpmgr that has been
done during 0.4.13dev'ing.

------------
Dedicated to the hard work of Joachim Henze! xD

This reverts part of commit 043a98dd (see also commit b2aeafca).

Contrary to what I assumed in commit 043a98dd (and was also assumed in
the older commit b2aeafca), we cannot use the singled-linked lists to
queue and dequeue the PnP device-install events, because:

- the events must be treated from the oldest to the newest ones, for
  consistency, otherwise this creates problems, as shown by e.g. CORE-16103;

- the system singled-linked lists only offer access to the top of the
  list (like a stack) instead of to both the top and the bottom of the
  list, as would be required for a queue. Using the SLISTs would mean
  that only the newest-received events would be treated first, while the
  oldest (which were the first received) events would be treated last,
  and this is wrong.

Therefore one must use e.g. the standard doubly-linked list. Also, using
locked operations (insertion & removal) on the list of device-install
events is necessary, because these operations are done concurrently by
two different threads: PnpEventThread() and DeviceInstallThread().
Since the interlocked linked list functions are not available in user-mode,
we need to use instead locking access through e.g. a mutex.

base/services/umpnpmgr/umpnpmgr.c
base/setup/usetup/devinst.c

index 656a89d..cd0d69a 100644 (file)
@@ -68,12 +68,12 @@ static HANDLE hUserToken = NULL;
 static HANDLE hInstallEvent = NULL;
 static HANDLE hNoPendingInstalls = NULL;
 
-static SLIST_HEADER DeviceInstallListHead;
+static LIST_ENTRY DeviceInstallListHead;
 static HANDLE hDeviceInstallListNotEmpty;
 
 typedef struct
 {
-    SLIST_ENTRY ListEntry;
+    LIST_ENTRY ListEntry;
     WCHAR DeviceIds[1];
 } DeviceInstallParams;
 
@@ -4097,7 +4097,7 @@ cleanup:
 static DWORD WINAPI
 DeviceInstallThread(LPVOID lpParameter)
 {
-    PSLIST_ENTRY ListEntry;
+    PLIST_ENTRY ListEntry;
     DeviceInstallParams* Params;
     BOOL showWizard;
 
@@ -4109,7 +4109,10 @@ DeviceInstallThread(LPVOID lpParameter)
 
     while (TRUE)
     {
-        ListEntry = InterlockedPopEntrySList(&DeviceInstallListHead);
+        if ((BOOL)IsListEmpty(&DeviceInstallListHead))
+            ListEntry = NULL;
+        else
+            ListEntry = RemoveHeadList(&DeviceInstallListHead);
 
         if (ListEntry == NULL)
         {
@@ -4191,7 +4194,7 @@ PnpEventThread(LPVOID lpParameter)
                 if (Params)
                 {
                     wcscpy(Params->DeviceIds, PnpEvent->TargetDevice.DeviceIds);
-                    InterlockedPushEntrySList(&DeviceInstallListHead, &Params->ListEntry);
+                    InsertTailList(&DeviceInstallListHead, &Params->ListEntry);
                     SetEvent(hDeviceInstallListNotEmpty);
                 }
             }
@@ -4435,7 +4438,7 @@ InitializePnPManager(VOID)
         return dwError;
     }
 
-    InitializeSListHead(&DeviceInstallListHead);
+    InitializeListHead(&DeviceInstallListHead);
 
     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
                             L"System\\CurrentControlSet\\Enum",
index ea4333c..bdc9f01 100644 (file)
@@ -25,12 +25,14 @@ static HANDLE hNoPendingInstalls = NULL;
 static HANDLE hPnpThread = NULL;
 static HANDLE hDeviceInstallThread = NULL;
 
-static SLIST_HEADER DeviceInstallListHead;
+/* Device-install event list */
+static HANDLE hDeviceInstallListMutex = NULL;
+static LIST_ENTRY DeviceInstallListHead;
 static HANDLE hDeviceInstallListNotEmpty = NULL;
 
 typedef struct
 {
-    SLIST_ENTRY ListEntry;
+    LIST_ENTRY ListEntry;
     WCHAR DeviceIds[ANYSIZE_ARRAY];
 } DeviceInstallParams;
 
@@ -363,13 +365,17 @@ static ULONG NTAPI
 DeviceInstallThread(IN PVOID Parameter)
 {
     HINF hSetupInf = *(HINF*)Parameter;
-    PSLIST_ENTRY ListEntry;
+    PLIST_ENTRY ListEntry;
     DeviceInstallParams* Params;
     LARGE_INTEGER Timeout;
 
     for (;;)
     {
-        ListEntry = RtlInterlockedPopEntrySList(&DeviceInstallListHead);
+        /* Dequeue the next oldest device-install event */
+        NtWaitForSingleObject(hDeviceInstallListMutex, FALSE, NULL);
+        ListEntry = (IsListEmpty(&DeviceInstallListHead)
+                        ? NULL : RemoveHeadList(&DeviceInstallListHead));
+        NtReleaseMutant(hDeviceInstallListMutex, NULL);
 
         if (ListEntry == NULL)
         {
@@ -453,18 +459,23 @@ PnpEventThread(IN PVOID Parameter)
             ULONG len;
             ULONG DeviceIdLength;
 
-            DPRINT("Device enumerated event: %S\n", PnpEvent->TargetDevice.DeviceIds);
+            DPRINT("Device enumerated: %S\n", PnpEvent->TargetDevice.DeviceIds);
 
             DeviceIdLength = wcslen(PnpEvent->TargetDevice.DeviceIds);
             if (DeviceIdLength)
             {
-                /* Queue device install (will be dequeued by DeviceInstallThread) */
+                /* Allocate a new device-install event */
                 len = FIELD_OFFSET(DeviceInstallParams, DeviceIds) + (DeviceIdLength + 1) * sizeof(WCHAR);
                 Params = RtlAllocateHeap(ProcessHeap, 0, len);
                 if (Params)
                 {
                     wcscpy(Params->DeviceIds, PnpEvent->TargetDevice.DeviceIds);
-                    RtlInterlockedPushEntrySList(&DeviceInstallListHead, &Params->ListEntry);
+
+                    /* Queue the event (will be dequeued by DeviceInstallThread) */
+                    NtWaitForSingleObject(hDeviceInstallListMutex, FALSE, NULL);
+                    InsertTailList(&DeviceInstallListHead, &Params->ListEntry);
+                    NtReleaseMutant(hDeviceInstallListMutex, NULL);
+
                     NtSetEvent(hDeviceInstallListNotEmpty, NULL);
                 }
                 else
@@ -551,29 +562,41 @@ InitializeUserModePnpManager(
     UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
     UNICODE_STRING ServicesU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
 
-    Status = NtCreateEvent(&hDeviceInstallListNotEmpty,
+    Status = NtCreateEvent(&hNoPendingInstalls,
                            EVENT_ALL_ACCESS,
                            NULL,
-                           SynchronizationEvent,
+                           NotificationEvent,
                            FALSE);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("Could not create the event! (Status 0x%08lx)\n", Status);
+        DPRINT1("Could not create the Pending-Install Event! (Status 0x%08lx)\n", Status);
         goto Failure;
     }
 
-    Status = NtCreateEvent(&hNoPendingInstalls,
+    /*
+     * Initialize the device-install event list
+     */
+
+    Status = NtCreateEvent(&hDeviceInstallListNotEmpty,
                            EVENT_ALL_ACCESS,
                            NULL,
-                           NotificationEvent,
+                           SynchronizationEvent,
                            FALSE);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("Could not create the event! (Status 0x%08lx)\n", Status);
+        DPRINT1("Could not create the List Event! (Status 0x%08lx)\n", Status);
         goto Failure;
     }
 
-    RtlInitializeSListHead(&DeviceInstallListHead);
+    Status = NtCreateMutant(&hDeviceInstallListMutex,
+                            MUTANT_ALL_ACCESS,
+                            NULL, FALSE);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Could not create the List Mutex! (Status 0x%08lx)\n", Status);
+        goto Failure;
+    }
+    InitializeListHead(&DeviceInstallListHead);
 
     InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_CASE_INSENSITIVE, NULL, NULL);
     Status = NtOpenKey(&hEnumKey, KEY_QUERY_VALUE, &ObjectAttributes);
@@ -645,14 +668,18 @@ Failure:
         NtClose(hEnumKey);
     hEnumKey = NULL;
 
-    if (hNoPendingInstalls)
-        NtClose(hNoPendingInstalls);
-    hNoPendingInstalls = NULL;
+    if (hDeviceInstallListMutex)
+        NtClose(hDeviceInstallListMutex);
+    hDeviceInstallListMutex = NULL;
 
     if (hDeviceInstallListNotEmpty)
         NtClose(hDeviceInstallListNotEmpty);
     hDeviceInstallListNotEmpty = NULL;
 
+    if (hNoPendingInstalls)
+        NtClose(hNoPendingInstalls);
+    hNoPendingInstalls = NULL;
+
     return Status;
 }