diff --git a/build/VStudio/winfsp.vcxproj b/build/VStudio/winfsp.vcxproj
index f7d94004..4b118dde 100644
--- a/build/VStudio/winfsp.vcxproj
+++ b/build/VStudio/winfsp.vcxproj
@@ -149,6 +149,7 @@
+
diff --git a/build/VStudio/winfsp.vcxproj.filters b/build/VStudio/winfsp.vcxproj.filters
index eb72665c..fba2a105 100644
--- a/build/VStudio/winfsp.vcxproj.filters
+++ b/build/VStudio/winfsp.vcxproj.filters
@@ -77,6 +77,9 @@
Source
+
+ Source
+
diff --git a/src/sys/driver.h b/src/sys/driver.h
index a897b3c5..8783c066 100644
--- a/src/sys/driver.h
+++ b/src/sys/driver.h
@@ -155,12 +155,24 @@ typedef struct
} FSP_IOQ;
VOID FspIoqInitialize(FSP_IOQ *Ioq);
VOID FspIoqEnable(FSP_IOQ *Ioq, int Delta);
+PKEVENT FspIoqPendingIrpEvent(FSP_IOQ *Ioq);
BOOLEAN FspIoqPostIrp(FSP_IOQ *Ioq, PIRP Irp);
PIRP FspIoqNextPendingIrp(FSP_IOQ *Ioq, ULONG millis);
BOOLEAN FspIoqStartProcessingIrp(FSP_IOQ *Ioq, PIRP Irp);
PIRP FspIoqEndProcessingIrp(FSP_IOQ *Ioq, UINT_PTR IrpHint);
VOID FspIoqCancelAll(FSP_IOQ *Ioq);
+/* transact thread */
+typedef struct
+{
+ PKTHREAD Thread;
+ KEVENT Event;
+ FSP_IOQ *TransactIoq, *Ioq;
+} FSP_TRANSACT_THREAD;
+NTSTATUS FspTransactThreadStart(FSP_TRANSACT_THREAD *TransactThread,
+ FSP_IOQ *TransactIoq, FSP_IOQ *Ioq);
+VOID FspTransactThreadStop(FSP_TRANSACT_THREAD *TransactThread);
+
/* device extensions */
enum
{
diff --git a/src/sys/ioq.c b/src/sys/ioq.c
index 384d9ec4..8a7f9e10 100644
--- a/src/sys/ioq.c
+++ b/src/sys/ioq.c
@@ -174,6 +174,11 @@ VOID FspIoqEnable(FSP_IOQ *Ioq, int Delta)
KeReleaseSpinLock(&Ioq->SpinLock, Irql);
}
+PKEVENT FspIoqPendingIrpEvent(FSP_IOQ *Ioq)
+{
+ return &Ioq->PendingIrpEvent;
+}
+
BOOLEAN FspIoqPostIrp(FSP_IOQ *Ioq, PIRP Irp)
{
NTSTATUS Result;
@@ -190,7 +195,7 @@ PIRP FspIoqNextPendingIrp(FSP_IOQ *Ioq, ULONG millis)
Timeout.QuadPart = (LONGLONG)millis * 10000;
Result = KeWaitForSingleObject(&Ioq->PendingIrpEvent, Executive, KernelMode, FALSE,
-1 == millis ? 0 : &Timeout);
- if (!NT_SUCCESS(Result))
+ if (STATUS_SUCCESS != Result)
return 0;
}
return IoCsqRemoveNextIrp(&Ioq->PendingIoCsq, (PVOID)1);
diff --git a/src/sys/transact.c b/src/sys/transact.c
new file mode 100644
index 00000000..e9dcff6f
--- /dev/null
+++ b/src/sys/transact.c
@@ -0,0 +1,82 @@
+/**
+ * @file sys/transact.c
+ *
+ * @copyright 2015 Bill Zissimopoulos
+ */
+
+#include
+
+static KSTART_ROUTINE FspTransactThread;
+NTSTATUS FspTransactThreadStart(FSP_TRANSACT_THREAD *TransactThread,
+ FSP_IOQ *TransactIoq, FSP_IOQ *Ioq);
+VOID FspTransactThreadStop(FSP_TRANSACT_THREAD *TransactThread);
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, FspTransactThread)
+#pragma alloc_text(PAGE, FspTransactThreadStart)
+#pragma alloc_text(PAGE, FspTransactThreadStop)
+#endif
+
+static VOID FspTransactThread(PVOID StartContext)
+{
+ PAGED_CODE();
+
+ FSP_TRANSACT_THREAD *TransactThread = StartContext;
+ PVOID WaitObjects[2];
+ WaitObjects[0] = &TransactThread->Event;
+ WaitObjects[1] = FspIoqPendingIrpEvent(TransactThread->TransactIoq);
+ for (;;)
+ {
+ NTSTATUS Result;
+ PIRP Irp;
+
+ Result = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, Executive, KernelMode, FALSE, 0, 0);
+ if (STATUS_WAIT_0 == Result)
+ break; /* stop thread */
+ else if (STATUS_WAIT_1 != Result)
+ continue; /* retry */
+
+ Irp = FspIoqNextPendingIrp(&TransactThread->TransactIoq, 0);
+ if (0 == Irp)
+ continue; /* retry */
+ }
+
+ PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+NTSTATUS FspTransactThreadStart(FSP_TRANSACT_THREAD *TransactThread,
+ FSP_IOQ *TransactIoq, FSP_IOQ *Ioq)
+{
+ PAGED_CODE();
+
+ NTSTATUS Result;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE ThreadHandle;
+
+ RtlZeroMemory(TransactThread, sizeof *TransactThread);
+ KeInitializeEvent(&TransactThread->Event, NotificationEvent, FALSE);
+ TransactThread->TransactIoq = TransactIoq;
+ TransactThread->Ioq = Ioq;
+
+ InitializeObjectAttributes(&ObjectAttributes, 0, OBJ_KERNEL_HANDLE, 0, 0);
+ Result = PsCreateSystemThread(&ThreadHandle, THREAD_ALL_ACCESS, &ObjectAttributes, 0, 0,
+ FspTransactThread, TransactThread);
+ if (!NT_SUCCESS(Result))
+ return Result;
+
+ Result = ObReferenceObjectByHandle(ThreadHandle, THREAD_ALL_ACCESS, *PsThreadType, KernelMode,
+ &TransactThread->Thread, 0);
+ ASSERT(NT_SUCCESS(Result));
+
+ ZwClose(ThreadHandle);
+
+ return STATUS_SUCCESS;
+}
+
+VOID FspTransactThreadStop(FSP_TRANSACT_THREAD *TransactThread)
+{
+ PAGED_CODE();
+
+ KeSetEvent(&TransactThread->Event, 1, TRUE);
+ KeWaitForSingleObject(&TransactThread->Thread, Executive, KernelMode, FALSE, 0);
+}