[ros-dev] KQUEUE race condition

Filip Navara xnavara at volny.cz
Sun Nov 21 14:25:32 CET 2004


Filip Navara wrote:

> Hi,
>
> I think I found a race condition in KQUEUE code, but I'm not sure my 
> solution is optimal. If no items are queued, KeRemoveQueue calls 
> KeWaitForSingleObject and then after it finishes it acquires 
> dispatcher lock and removes a list item. The problem arises when 
> someone calls KeRemoveQueue just after the KeWaitForSingleObject call 
> finishes and before the dispatcher lock is acquired. In this case he 
> can remove the last item in the list and this will cause the first 
> KeRemoveQueue (the one that waited) to return garbage. Can anybody 
> think of better solution than the attached patch?
>
> Regards,
> Filip

Now with a corrected patch...
-------------- next part --------------
Index: ntoskrnl/ke/queue.c
===================================================================
RCS file: /CVS/ReactOS/reactos/ntoskrnl/ke/queue.c,v
retrieving revision 1.11
diff -u -r1.11 queue.c
--- ntoskrnl/ke/queue.c	15 Aug 2004 16:39:05 -0000	1.11
+++ ntoskrnl/ke/queue.c	21 Nov 2004 13:21:52 -0000
@@ -159,27 +159,41 @@
       return ListEntry;
    }
 
-   //need to wait for it...
-   KeReleaseDispatcherDatabaseLock (OldIrql);
-
-   Status = KeWaitForSingleObject(Queue,
-                                  WrQueue,
-                                  WaitMode,
-                                  TRUE,//Alertable,
-                                  Timeout);
-
-   if (Status == STATUS_TIMEOUT || Status == STATUS_USER_APC)
-   {
-      return (PVOID)Status;
-   }
-   else
+   for (;;)
    {
-      OldIrql = KeAcquireDispatcherDatabaseLock ();
-      ListEntry = RemoveHeadList(&Queue->EntryListHead);
+      //need to wait for it...
       KeReleaseDispatcherDatabaseLock (OldIrql);
-      return ListEntry;
-   }
 
+      Status = KeWaitForSingleObject(Queue,
+                                     WrQueue,
+                                     WaitMode,
+                                     TRUE,//Alertable,
+                                     Timeout);
+
+      if (Status == STATUS_TIMEOUT || Status == STATUS_USER_APC)
+      {
+         return (PVOID)Status;
+      }
+      else
+      {
+         OldIrql = KeAcquireDispatcherDatabaseLock ();
+
+         /*
+          * Prevent a race condition. If someone calls KeRemoveQueue
+          * just after we end up waiting and before acquiring the spin
+          * lock he can get the last item in the list...
+          */
+         if (IsListEmpty(&Queue->EntryListHead))
+         {
+            Queue->Header.SignalState++;
+            continue;
+         }
+
+         ListEntry = RemoveHeadList(&Queue->EntryListHead);
+         KeReleaseDispatcherDatabaseLock (OldIrql);
+         return ListEntry;
+      }
+   }
 }
 
 


More information about the Ros-dev mailing list