[MSFS]
authorPierre Schweitzer <pierre@reactos.org>
Sat, 10 Oct 2015 08:29:05 +0000 (08:29 +0000)
committerPierre Schweitzer <pierre@reactos.org>
Sat, 10 Oct 2015 08:29:05 +0000 (08:29 +0000)
Implement asynchronous reading from mailslot.
Patch by Nikita Pechenkin

Adjustements, style fixing by myself.

CORE-10245 #resolve #comment Modified patch committed with r69475. I have tested kernel32:mailslot and your provided test, both are passing 100%. Thanks!

svn path=/trunk/; revision=69475

reactos/drivers/filesystems/msfs/CMakeLists.txt
reactos/drivers/filesystems/msfs/create.c
reactos/drivers/filesystems/msfs/msfs.h
reactos/drivers/filesystems/msfs/rw.c

index f40db6f..629803e 100644 (file)
@@ -5,6 +5,7 @@ list(APPEND SOURCE
     fsctrl.c
     msfs.c
     rw.c
+    msfssup.c
     msfs.h)
 
 add_library(msfs SHARED ${SOURCE} msfs.rc)
index ec62287..036b4ca 100644 (file)
@@ -4,6 +4,7 @@
  * FILE:       drivers/filesystems/msfs/create.c
  * PURPOSE:    Mailslot filesystem
  * PROGRAMMER: Eric Kohl
+ *             Nikita Pechenkin (n.pechenkin@mail.ru)
  */
 
 /* INCLUDES ******************************************************************/
@@ -183,6 +184,17 @@ MsfsCreateMailslot(PDEVICE_OBJECT DeviceObject,
     InitializeListHead(&Fcb->MessageListHead);
     KeInitializeSpinLock(&Fcb->MessageListLock);
 
+    Fcb->WaitCount = 0;
+    KeInitializeSpinLock(&Fcb->QueueLock);
+    InitializeListHead(&Fcb->PendingIrpQueue);
+    IoCsqInitialize(&Fcb->CancelSafeQueue,
+                    MsfsInsertIrp,
+                    MsfsRemoveIrp,
+                    MsfsPeekNextIrp,
+                    MsfsAcquireLock,
+                    MsfsReleaseLock,
+                    MsfsCompleteCanceledIrp);
+
     KeLockMutex(&DeviceExtension->FcbListLock);
     current_entry = DeviceExtension->FcbListHead.Flink;
     while (current_entry != &DeviceExtension->FcbListHead)
index ecc0b7a..402a7b5 100644 (file)
@@ -4,12 +4,14 @@
  * FILE:       drivers/filesystems/msfs/msfs.h
  * PURPOSE:    Mailslot filesystem
  * PROGRAMMER: Eric Kohl
+ *             Nikita Pechenkin (n.pechenkin@mail.ru)
  */
 
 #ifndef __DRIVERS_FS_MS_MSFS_H
 #define __DRIVERS_FS_MS_MSFS_H
 
 #include <ntifs.h>
+#include <wdm.h>
 
 #define DEFAULTAPI NTAPI
 
@@ -35,9 +37,22 @@ typedef struct _MSFS_FCB
     ULONG MessageCount;
     KSPIN_LOCK MessageListLock;
     LIST_ENTRY MessageListHead;
+    IO_CSQ CancelSafeQueue;
+    KSPIN_LOCK QueueLock;
+    LIST_ENTRY PendingIrpQueue;
+    ULONG WaitCount;
 } MSFS_FCB, *PMSFS_FCB;
 
 
+typedef struct _MSFS_DPC_CTX
+{
+    KTIMER Timer;
+    KDPC Dpc;
+    PIO_CSQ Csq;
+    IO_CSQ_IRP_CONTEXT CsqContext;
+} MSFS_DPC_CTX, *PMSFS_DPC_CTX;
+
+
 typedef struct _MSFS_CCB
 {
     LIST_ENTRY CcbListEntry;
@@ -89,4 +104,35 @@ NTSTATUS NTAPI
 DriverEntry(PDRIVER_OBJECT DriverObject,
             PUNICODE_STRING RegistryPath);
 
+IO_CSQ_INSERT_IRP MsfsInsertIrp;
+VOID NTAPI
+MsfsInsertIrp(PIO_CSQ Csq, PIRP Irp);
+
+IO_CSQ_REMOVE_IRP MsfsRemoveIrp;
+VOID NTAPI
+MsfsRemoveIrp(PIO_CSQ Csq, PIRP Irp);
+
+IO_CSQ_PEEK_NEXT_IRP MsfsPeekNextIrp;
+PIRP NTAPI
+MsfsPeekNextIrp(PIO_CSQ Csq, PIRP Irp, PVOID PeekContext);
+
+IO_CSQ_ACQUIRE_LOCK MsfsAcquireLock;
+VOID NTAPI
+MsfsAcquireLock(PIO_CSQ Csq, PKIRQL Irql);
+
+IO_CSQ_RELEASE_LOCK MsfsReleaseLock;
+VOID NTAPI
+MsfsReleaseLock(PIO_CSQ Csq, KIRQL Irql);
+
+IO_CSQ_COMPLETE_CANCELED_IRP MsfsCompleteCanceledIrp;
+VOID NTAPI
+MsfsCompleteCanceledIrp(PIO_CSQ pCsq, PIRP Irp);
+
+KDEFERRED_ROUTINE MsfsTimeout;
+VOID NTAPI
+MsfsTimeout(PKDPC Dpc,
+            PVOID DeferredContext,
+            PVOID SystemArgument1,
+            PVOID SystemArgument2);
+
 #endif /* __DRIVERS_FS_MS_MSFS_H */
index c194fb2..188a578 100644 (file)
@@ -4,6 +4,7 @@
  * FILE:       drivers/filesystems/msfs/rw.c
  * PURPOSE:    Mailslot filesystem
  * PROGRAMMER: Eric Kohl
+ *             Nikita Pechenkin (n.pechenkin@mail.ru)
  */
 
 /* INCLUDES ******************************************************************/
@@ -28,8 +29,10 @@ MsfsRead(PDEVICE_OBJECT DeviceObject,
     ULONG Length;
     ULONG LengthRead = 0;
     PVOID Buffer;
-    NTSTATUS Status;
-    PLARGE_INTEGER Timeout;
+    LARGE_INTEGER Timeout;
+    PKTIMER Timer;
+    PMSFS_DPC_CTX Context;
+    PKDPC Dpc;
 
     DPRINT("MsfsRead(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
 
@@ -57,52 +60,74 @@ MsfsRead(PDEVICE_OBJECT DeviceObject,
     else
         Buffer = Irp->UserBuffer;
 
-    if (Fcb->TimeOut.QuadPart == -1LL)
-        Timeout = NULL;
-    else
-        Timeout = &Fcb->TimeOut;
-
-    Status = KeWaitForSingleObject(&Fcb->MessageEvent,
-                                   UserRequest,
-                                   UserMode,
-                                   FALSE,
-                                   Timeout);
-    if (Status != STATUS_USER_APC)
+
+    if (Fcb->MessageCount > 0)
     {
-        if (Fcb->MessageCount > 0)
-        {
-            /* copy current message into buffer */
-            Message = CONTAINING_RECORD(Fcb->MessageListHead.Flink,
-                                        MSFS_MESSAGE,
-                                        MessageListEntry);
-
-            memcpy(Buffer, &Message->Buffer, min(Message->Size,Length));
-            LengthRead = Message->Size;
-
-            KeAcquireSpinLock(&Fcb->MessageListLock, &oldIrql);
-            RemoveHeadList(&Fcb->MessageListHead);
-            KeReleaseSpinLock(&Fcb->MessageListLock, oldIrql);
-
-            ExFreePoolWithTag(Message, 'rFsM');
-            Fcb->MessageCount--;
-            if (Fcb->MessageCount == 0)
-            {
-                KeClearEvent(&Fcb->MessageEvent);
-            }
-        }
-        else
+        /* copy current message into buffer */
+        Message = CONTAINING_RECORD(Fcb->MessageListHead.Flink,
+                                    MSFS_MESSAGE,
+                                    MessageListEntry);
+
+        memcpy(Buffer, &Message->Buffer, min(Message->Size,Length));
+        LengthRead = Message->Size;
+
+        KeAcquireSpinLock(&Fcb->MessageListLock, &oldIrql);
+        RemoveHeadList(&Fcb->MessageListHead);
+        KeReleaseSpinLock(&Fcb->MessageListLock, oldIrql);
+
+        ExFreePoolWithTag(Message, 'rFsM');
+        Fcb->MessageCount--;
+        if (Fcb->MessageCount == 0)
         {
-            /* No message found after waiting */
-            Status = STATUS_IO_TIMEOUT;
+            KeClearEvent(&Fcb->MessageEvent);
         }
-     }
 
-    Irp->IoStatus.Status = Status;
-    Irp->IoStatus.Information = LengthRead;
+        Irp->IoStatus.Status = STATUS_SUCCESS;
+        Irp->IoStatus.Information = LengthRead;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        return STATUS_SUCCESS;
+    }
+
+    Timeout = Fcb->TimeOut;
+    if (Timeout.HighPart == 0 && Timeout.LowPart == 0)
+    {
+        Irp->IoStatus.Status = STATUS_IO_TIMEOUT;
+        Irp->IoStatus.Information = 0;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+        return STATUS_IO_TIMEOUT;
+    }
+
+    Context = ExAllocatePoolWithTag(NonPagedPool, sizeof(MSFS_DPC_CTX), 'NFsM');
+    if (Context == NULL)
+    {
+        Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+        Irp->IoStatus.Information = 0;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    IoCsqInsertIrp(&Fcb->CancelSafeQueue, Irp, &Context->CsqContext);
+    Timer = &Context->Timer;
+    Dpc = &Context->Dpc;
+    Context->Csq = &Fcb->CancelSafeQueue;
 
-    return Status;
+    /* No timer for INFINITY_WAIT */
+    if (Timeout.QuadPart != -1)
+    {
+        KeInitializeTimer(Timer);
+        KeInitializeDpc(Dpc, MsfsTimeout, (PVOID)Context);
+        KeSetTimer(Timer, Timeout, Dpc);
+    }
+
+    Fcb->WaitCount++;
+    Irp->IoStatus.Status = STATUS_PENDING;
+    Irp->IoStatus.Information = 0;
+    IoMarkIrpPending(Irp);
+
+    return STATUS_PENDING;
 }
 
 
@@ -118,6 +143,7 @@ MsfsWrite(PDEVICE_OBJECT DeviceObject,
     KIRQL oldIrql;
     ULONG Length;
     PVOID Buffer;
+    PIRP CsqIrp;
 
     DPRINT("MsfsWrite(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
 
@@ -176,6 +202,14 @@ MsfsWrite(PDEVICE_OBJECT DeviceObject,
                    FALSE);
     }
 
+    if (Fcb->WaitCount > 0)
+    {
+        CsqIrp = IoCsqRemoveNextIrp(&Fcb->CancelSafeQueue, NULL);
+        /* FIXME: It is necessary to reset the timers. */
+        MsfsRead(DeviceObject, CsqIrp);
+        Fcb->WaitCount--;
+    }
+
     Irp->IoStatus.Status = STATUS_SUCCESS;
     Irp->IoStatus.Information = Length;