NTSTATUS EncryptedIoQueueStop (EncryptedIoQueue *queue) { ASSERT (!queue->StopPending); queue->StopPending = TRUE; while (InterlockedExchangeAdd (&queue->OutstandingIoCount, 0) > 0) { KeWaitForSingleObject (&queue->NoOutstandingIoEvent, Executive, KernelMode, FALSE, NULL); } Dump ("Queue stopping out=%d\n", queue->OutstandingIoCount); queue->ThreadExitRequested = TRUE; TCStopThread (queue->MainThread, &queue->MainThreadQueueNotEmptyEvent); TCStopThread (queue->IoThread, &queue->IoThreadQueueNotEmptyEvent); TCStopThread (queue->CompletionThread, &queue->CompletionThreadQueueNotEmptyEvent); TCfree (queue->FragmentBufferA); TCfree (queue->FragmentBufferB); TCfree (queue->ReadAheadBuffer); FreePoolBuffers (queue); Dump ("Queue stopped out=%d\n", queue->OutstandingIoCount); return STATUS_SUCCESS; }
NTSTATUS EncryptedIoQueueStart (EncryptedIoQueue *queue) { NTSTATUS status; EncryptedIoQueueBuffer *buffer; int i; queue->StartPending = TRUE; queue->ThreadExitRequested = FALSE; queue->OutstandingIoCount = 0; queue->IoThreadPendingRequestCount = 0; queue->FirstPoolBuffer = NULL; KeInitializeMutex (&queue->BufferPoolMutex, 0); KeInitializeEvent (&queue->NoOutstandingIoEvent, SynchronizationEvent, FALSE); KeInitializeEvent (&queue->PoolBufferFreeEvent, SynchronizationEvent, FALSE); KeInitializeEvent (&queue->QueueResumedEvent, SynchronizationEvent, FALSE); queue->FragmentBufferA = TCalloc (TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE); if (!queue->FragmentBufferA) goto noMemory; queue->FragmentBufferB = TCalloc (TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE); if (!queue->FragmentBufferB) goto noMemory; KeInitializeEvent (&queue->FragmentBufferAFreeEvent, SynchronizationEvent, TRUE); KeInitializeEvent (&queue->FragmentBufferBFreeEvent, SynchronizationEvent, TRUE); queue->ReadAheadBufferValid = FALSE; queue->ReadAheadBuffer = TCalloc (TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE); if (!queue->ReadAheadBuffer) goto noMemory; // Preallocate buffers for (i = 0; i < TC_ENC_IO_QUEUE_PREALLOCATED_IO_REQUEST_COUNT; ++i) { if (i < TC_ENC_IO_QUEUE_PREALLOCATED_ITEM_COUNT && !GetPoolBuffer (queue, sizeof (EncryptedIoQueueItem))) goto noMemory; if (!GetPoolBuffer (queue, sizeof (EncryptedIoRequest))) goto noMemory; } for (buffer = queue->FirstPoolBuffer; buffer != NULL; buffer = buffer->NextBuffer) { buffer->InUse = FALSE; } // Main thread InitializeListHead (&queue->MainThreadQueue); KeInitializeSpinLock (&queue->MainThreadQueueLock); KeInitializeEvent (&queue->MainThreadQueueNotEmptyEvent, SynchronizationEvent, FALSE); status = TCStartThread (MainThreadProc, queue, &queue->MainThread); if (!NT_SUCCESS (status)) goto err; // IO thread InitializeListHead (&queue->IoThreadQueue); KeInitializeSpinLock (&queue->IoThreadQueueLock); KeInitializeEvent (&queue->IoThreadQueueNotEmptyEvent, SynchronizationEvent, FALSE); status = TCStartThread (IoThreadProc, queue, &queue->IoThread); if (!NT_SUCCESS (status)) { queue->ThreadExitRequested = TRUE; TCStopThread (queue->MainThread, &queue->MainThreadQueueNotEmptyEvent); goto err; } // Completion thread InitializeListHead (&queue->CompletionThreadQueue); KeInitializeSpinLock (&queue->CompletionThreadQueueLock); KeInitializeEvent (&queue->CompletionThreadQueueNotEmptyEvent, SynchronizationEvent, FALSE); status = TCStartThread (CompletionThreadProc, queue, &queue->CompletionThread); if (!NT_SUCCESS (status)) { queue->ThreadExitRequested = TRUE; TCStopThread (queue->MainThread, &queue->MainThreadQueueNotEmptyEvent); TCStopThread (queue->IoThread, &queue->IoThreadQueueNotEmptyEvent); goto err; } #ifdef TC_TRACE_IO_QUEUE GetElapsedTimeInit (&queue->LastPerformanceCounter); #endif queue->StopPending = FALSE; queue->StartPending = FALSE; Dump ("Queue started\n"); return STATUS_SUCCESS; noMemory: status = STATUS_INSUFFICIENT_RESOURCES; err: if (queue->FragmentBufferA) TCfree (queue->FragmentBufferA); if (queue->FragmentBufferB) TCfree (queue->FragmentBufferB); if (queue->ReadAheadBuffer) TCfree (queue->ReadAheadBuffer); FreePoolBuffers (queue); queue->StartPending = FALSE; return status; }