VOID PkUpdateArchiveExtractCallback::Run() { HRESULT result; IInArchive *currentArchive; PhAcquireQueuedLockExclusive(&Lock); while (!ThreadStopping) { if (!InArchive) { PhWaitForCondition(&Condition, &Lock, NULL); continue; } currentArchive = InArchive; currentArchive->AddRef(); result = currentArchive->Extract(NULL, -1, FALSE, this); currentArchive->Release(); if (result != E_ABORT && !SUCCEEDED(result)) Result = result; } PhReleaseQueuedLockExclusive(&Lock); }
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::WaitForJob() { PhAcquireQueuedLockExclusive(&Lock); while (InArchive && ItemIndex != -1) PhWaitForCondition(&Condition, &Lock, NULL); PhReleaseQueuedLockExclusive(&Lock); }
/** * Waits for all queued work items to be executed. * * \param WorkQueue A work queue object. */ VOID PhWaitForWorkQueue( _Inout_ PPH_WORK_QUEUE WorkQueue ) { PhAcquireQueuedLockExclusive(&WorkQueue->QueueLock); while (!IsListEmpty(&WorkQueue->QueueListHead)) PhWaitForCondition(&WorkQueue->QueueEmptyCondition, &WorkQueue->QueueLock, NULL); PhReleaseQueuedLockExclusive(&WorkQueue->QueueLock); }
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; } }
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; }