VOID PkUpdateArchiveExtractCallback::SetNewJob(IInArchive *NewInArchive, ULONG NewItemIndex, IOutStream *NewOutStream) { PhAcquireQueuedLockExclusive(&Lock); // Wait for the current job to finish. while (!ThreadStopping && ItemIndex != -1) PhWaitForCondition(&Condition, &Lock, NULL); if (ThreadStopping) return; if (NewInArchive) NewInArchive->AddRef(); if (InArchive) InArchive->Release(); InArchive = NewInArchive; ItemIndex = NewItemIndex; if (NewOutStream) NewOutStream->AddRef(); if (OutStream) OutStream->Release(); OutStream = NewOutStream; PhPulseCondition(&Condition); PhReleaseQueuedLockExclusive(&Lock); }
VOID PkUpdateArchiveExtractCallback::StopThread() { SetNewJob(NULL, -1, NULL); PhAcquireQueuedLockExclusive(&Lock); ThreadStopping = TRUE; PhPulseCondition(&Condition); PhReleaseQueuedLockExclusive(&Lock); }
HRESULT PkUpdateArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) { IInArchive *currentArchive; // This code executes with the lock held. currentArchive = InArchive; // Wait until we get a job or the archive has changed. while (!ThreadStopping && InArchive == currentArchive && ItemIndex == -1) { PhWaitForCondition(&Condition, &Lock, NULL); } if (InArchive != currentArchive) return E_ABORT; if (index < ItemIndex) { // Keep searching. *outStream = &(new PkFileStream(PkZeroFileStream, NULL))->OutStream; return S_OK; } else if (index == ItemIndex) { *outStream = OutStream; OutStream = NULL; ItemIndex = -1; PhPulseCondition(&Condition); return S_OK; } else { // We've gone past the item. return E_ABORT; } }
NTSTATUS PhpWorkQueueThreadStart( _In_ PVOID Parameter ) { PPH_WORK_QUEUE workQueue = (PPH_WORK_QUEUE)Parameter; while (TRUE) { NTSTATUS status; HANDLE semaphoreHandle; LARGE_INTEGER timeout; PPH_WORK_QUEUE_ITEM workQueueItem = NULL; // Check if we have more threads than the limit. if (workQueue->CurrentThreads > workQueue->MaximumThreads) { BOOLEAN terminate = FALSE; // Lock and re-check. PhAcquireQueuedLockExclusive(&workQueue->StateLock); // Check the minimum as well. if (workQueue->CurrentThreads > workQueue->MaximumThreads && workQueue->CurrentThreads > workQueue->MinimumThreads) { workQueue->CurrentThreads--; terminate = TRUE; } PhReleaseQueuedLockExclusive(&workQueue->StateLock); if (terminate) break; } semaphoreHandle = PhpGetSemaphoreWorkQueue(workQueue); if (!workQueue->Terminating) { // Wait for work. status = NtWaitForSingleObject( semaphoreHandle, FALSE, PhTimeoutFromMilliseconds(&timeout, workQueue->NoWorkTimeout) ); } else { status = STATUS_UNSUCCESSFUL; } if (status == STATUS_WAIT_0 && !workQueue->Terminating) { PLIST_ENTRY listEntry; // Dequeue the work item. PhAcquireQueuedLockExclusive(&workQueue->QueueLock); listEntry = RemoveHeadList(&workQueue->QueueListHead); if (IsListEmpty(&workQueue->QueueListHead)) PhPulseCondition(&workQueue->QueueEmptyCondition); PhReleaseQueuedLockExclusive(&workQueue->QueueLock); // Make sure we got work. if (listEntry != &workQueue->QueueListHead) { workQueueItem = CONTAINING_RECORD(listEntry, PH_WORK_QUEUE_ITEM, ListEntry); PhpExecuteWorkQueueItem(workQueueItem); _InterlockedDecrement(&workQueue->BusyCount); PhpDestroyWorkQueueItem(workQueueItem); } } else { BOOLEAN terminate = FALSE; // No work arrived before the timeout passed, or we are terminating, or some error occurred. // Terminate the thread. PhAcquireQueuedLockExclusive(&workQueue->StateLock); if (workQueue->Terminating || workQueue->CurrentThreads > workQueue->MinimumThreads) { workQueue->CurrentThreads--; terminate = TRUE; } PhReleaseQueuedLockExclusive(&workQueue->StateLock); if (terminate) break; } } PhReleaseRundownProtection(&workQueue->RundownProtect); return STATUS_SUCCESS; }
HRESULT PkFileInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { NTSTATUS status; if (Parent->Mode == PkPipeReaderFileStream) { PkFileStream *parentPipe; PCHAR currentData; ULONG remainingSize; ULONG availableSize; parentPipe = Parent->ParentPipe; currentData = (PCHAR)data; remainingSize = size; PhAcquireQueuedLockExclusive(&parentPipe->PipeLock); while (remainingSize != 0 && parentPipe->RemainingStreamSize != 0) { if (parentPipe->ReadPosition == parentPipe->ReadableSize) { if (parentPipe->RemainingStreamSize == 0 || parentPipe->WriteReferenceCount == 0) break; PhPulseCondition(&parentPipe->PipeCondition); // Wait for the writer to fill up our buffer. PhWaitForCondition(&parentPipe->PipeCondition, &parentPipe->PipeLock, NULL); continue; } availableSize = (ULONG)(parentPipe->ReadableSize - parentPipe->ReadPosition); if (remainingSize >= availableSize) { memcpy(currentData, (PCHAR)parentPipe->Buffer + parentPipe->ReadPosition, availableSize); currentData += availableSize; parentPipe->ReadPosition += availableSize; if (parentPipe->RemainingStreamSize >= availableSize) parentPipe->RemainingStreamSize -= availableSize; else parentPipe->RemainingStreamSize = 0; remainingSize -= availableSize; } else { memcpy(currentData, (PCHAR)parentPipe->Buffer + parentPipe->ReadPosition, remainingSize); currentData += availableSize; parentPipe->ReadPosition += remainingSize; if (parentPipe->RemainingStreamSize >= remainingSize) parentPipe->RemainingStreamSize -= remainingSize; else parentPipe->RemainingStreamSize = 0; remainingSize = 0; } } PhReleaseQueuedLockExclusive(&parentPipe->PipeLock); *processedSize = size - remainingSize; return S_OK; } else if (Parent->Mode == PkPipeWriterFileStream) { return E_FAIL; } if (!Parent->FileStream) { *processedSize = 0; return S_OK; } *processedSize = 0; status = PhReadFileStream(Parent->FileStream, data, size, (PULONG)processedSize); if (status == STATUS_END_OF_FILE) { *processedSize = 0; return S_OK; } if (NT_SUCCESS(status)) return S_OK; else return E_FAIL; }
HRESULT PkFileOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { NTSTATUS status; if (Parent->Mode == PkPipeWriterFileStream) { PkFileStream *parentPipe; PCHAR currentData; SIZE_T remainingSize; parentPipe = Parent->ParentPipe; currentData = (PCHAR)data; remainingSize = size; PhAcquireQueuedLockExclusive(&parentPipe->PipeLock); while (remainingSize != 0) { if (parentPipe->ReadPosition != parentPipe->ReadableSize) { if (parentPipe->ReadReferenceCount == 0) break; // Wait for the reader to read everything. PhWaitForCondition(&parentPipe->PipeCondition, &parentPipe->PipeLock, NULL); continue; } if (remainingSize >= parentPipe->BufferSize) { memcpy(parentPipe->Buffer, currentData, parentPipe->BufferSize); currentData += parentPipe->BufferSize; parentPipe->ReadableSize = parentPipe->BufferSize; remainingSize -= parentPipe->BufferSize; } else { memcpy(parentPipe->Buffer, currentData, remainingSize); currentData += remainingSize; parentPipe->ReadableSize = remainingSize; remainingSize = 0; } parentPipe->ReadPosition = 0; PhPulseCondition(&parentPipe->PipeCondition); } PhReleaseQueuedLockExclusive(&parentPipe->PipeLock); *processedSize = size; return S_OK; } else if (Parent->Mode == PkPipeReaderFileStream) { return E_FAIL; } if (!Parent->FileStream) { *processedSize = size; return S_OK; } status = PhWriteFileStream(Parent->FileStream, (PVOID)data, size); *processedSize = size; if (NT_SUCCESS(status)) return S_OK; else return E_FAIL; }