Index: third_party/lzma_sdk/C/MtCoder.c |
=================================================================== |
--- third_party/lzma_sdk/C/MtCoder.c (revision 0) |
+++ third_party/lzma_sdk/C/MtCoder.c (revision 0) |
@@ -0,0 +1,327 @@ |
+/* MtCoder.c -- Multi-thread Coder |
+2010-09-24 : Igor Pavlov : Public domain */ |
+ |
+#include <stdio.h> |
+ |
+#include "MtCoder.h" |
+ |
+void LoopThread_Construct(CLoopThread *p) |
+{ |
+ Thread_Construct(&p->thread); |
+ Event_Construct(&p->startEvent); |
+ Event_Construct(&p->finishedEvent); |
+} |
+ |
+void LoopThread_Close(CLoopThread *p) |
+{ |
+ Thread_Close(&p->thread); |
+ Event_Close(&p->startEvent); |
+ Event_Close(&p->finishedEvent); |
+} |
+ |
+static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE LoopThreadFunc(void *pp) |
+{ |
+ CLoopThread *p = (CLoopThread *)pp; |
+ for (;;) |
+ { |
+ if (Event_Wait(&p->startEvent) != 0) |
+ return SZ_ERROR_THREAD; |
+ if (p->stop) |
+ return 0; |
+ p->res = p->func(p->param); |
+ if (Event_Set(&p->finishedEvent) != 0) |
+ return SZ_ERROR_THREAD; |
+ } |
+} |
+ |
+WRes LoopThread_Create(CLoopThread *p) |
+{ |
+ p->stop = 0; |
+ RINOK(AutoResetEvent_CreateNotSignaled(&p->startEvent)); |
+ RINOK(AutoResetEvent_CreateNotSignaled(&p->finishedEvent)); |
+ return Thread_Create(&p->thread, LoopThreadFunc, p); |
+} |
+ |
+WRes LoopThread_StopAndWait(CLoopThread *p) |
+{ |
+ p->stop = 1; |
+ if (Event_Set(&p->startEvent) != 0) |
+ return SZ_ERROR_THREAD; |
+ return Thread_Wait(&p->thread); |
+} |
+ |
+WRes LoopThread_StartSubThread(CLoopThread *p) { return Event_Set(&p->startEvent); } |
+WRes LoopThread_WaitSubThread(CLoopThread *p) { return Event_Wait(&p->finishedEvent); } |
+ |
+static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize) |
+{ |
+ return (p && p->Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK; |
+} |
+ |
+static void MtProgress_Init(CMtProgress *p, ICompressProgress *progress) |
+{ |
+ unsigned i; |
+ for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++) |
+ p->inSizes[i] = p->outSizes[i] = 0; |
+ p->totalInSize = p->totalOutSize = 0; |
+ p->progress = progress; |
+ p->res = SZ_OK; |
+} |
+ |
+static void MtProgress_Reinit(CMtProgress *p, unsigned index) |
+{ |
+ p->inSizes[index] = 0; |
+ p->outSizes[index] = 0; |
+} |
+ |
+#define UPDATE_PROGRESS(size, prev, total) \ |
+ if (size != (UInt64)(Int64)-1) { total += size - prev; prev = size; } |
+ |
+SRes MtProgress_Set(CMtProgress *p, unsigned index, UInt64 inSize, UInt64 outSize) |
+{ |
+ SRes res; |
+ CriticalSection_Enter(&p->cs); |
+ UPDATE_PROGRESS(inSize, p->inSizes[index], p->totalInSize) |
+ UPDATE_PROGRESS(outSize, p->outSizes[index], p->totalOutSize) |
+ if (p->res == SZ_OK) |
+ p->res = Progress(p->progress, p->totalInSize, p->totalOutSize); |
+ res = p->res; |
+ CriticalSection_Leave(&p->cs); |
+ return res; |
+} |
+ |
+static void MtProgress_SetError(CMtProgress *p, SRes res) |
+{ |
+ CriticalSection_Enter(&p->cs); |
+ if (p->res == SZ_OK) |
+ p->res = res; |
+ CriticalSection_Leave(&p->cs); |
+} |
+ |
+static void MtCoder_SetError(CMtCoder* p, SRes res) |
+{ |
+ CriticalSection_Enter(&p->cs); |
+ if (p->res == SZ_OK) |
+ p->res = res; |
+ CriticalSection_Leave(&p->cs); |
+} |
+ |
+/* ---------- MtThread ---------- */ |
+ |
+void CMtThread_Construct(CMtThread *p, CMtCoder *mtCoder) |
+{ |
+ p->mtCoder = mtCoder; |
+ p->outBuf = 0; |
+ p->inBuf = 0; |
+ Event_Construct(&p->canRead); |
+ Event_Construct(&p->canWrite); |
+ LoopThread_Construct(&p->thread); |
+} |
+ |
+#define RINOK_THREAD(x) { if((x) != 0) return SZ_ERROR_THREAD; } |
+ |
+static void CMtThread_CloseEvents(CMtThread *p) |
+{ |
+ Event_Close(&p->canRead); |
+ Event_Close(&p->canWrite); |
+} |
+ |
+static void CMtThread_Destruct(CMtThread *p) |
+{ |
+ CMtThread_CloseEvents(p); |
+ |
+ if (Thread_WasCreated(&p->thread.thread)) |
+ { |
+ LoopThread_StopAndWait(&p->thread); |
+ LoopThread_Close(&p->thread); |
+ } |
+ |
+ if (p->mtCoder->alloc) |
+ IAlloc_Free(p->mtCoder->alloc, p->outBuf); |
+ p->outBuf = 0; |
+ |
+ if (p->mtCoder->alloc) |
+ IAlloc_Free(p->mtCoder->alloc, p->inBuf); |
+ p->inBuf = 0; |
+} |
+ |
+#define MY_BUF_ALLOC(buf, size, newSize) \ |
+ if (buf == 0 || size != newSize) \ |
+ { IAlloc_Free(p->mtCoder->alloc, buf); \ |
+ size = newSize; buf = (Byte *)IAlloc_Alloc(p->mtCoder->alloc, size); \ |
+ if (buf == 0) return SZ_ERROR_MEM; } |
+ |
+static SRes CMtThread_Prepare(CMtThread *p) |
+{ |
+ MY_BUF_ALLOC(p->inBuf, p->inBufSize, p->mtCoder->blockSize) |
+ MY_BUF_ALLOC(p->outBuf, p->outBufSize, p->mtCoder->destBlockSize) |
+ |
+ p->stopReading = False; |
+ p->stopWriting = False; |
+ RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canRead)); |
+ RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canWrite)); |
+ |
+ return SZ_OK; |
+} |
+ |
+static SRes FullRead(ISeqInStream *stream, Byte *data, size_t *processedSize) |
+{ |
+ size_t size = *processedSize; |
+ *processedSize = 0; |
+ while (size != 0) |
+ { |
+ size_t curSize = size; |
+ SRes res = stream->Read(stream, data, &curSize); |
+ *processedSize += curSize; |
+ data += curSize; |
+ size -= curSize; |
+ RINOK(res); |
+ if (curSize == 0) |
+ return SZ_OK; |
+ } |
+ return SZ_OK; |
+} |
+ |
+#define GET_NEXT_THREAD(p) &p->mtCoder->threads[p->index == p->mtCoder->numThreads - 1 ? 0 : p->index + 1] |
+ |
+static SRes MtThread_Process(CMtThread *p, Bool *stop) |
+{ |
+ CMtThread *next; |
+ *stop = True; |
+ if (Event_Wait(&p->canRead) != 0) |
+ return SZ_ERROR_THREAD; |
+ |
+ next = GET_NEXT_THREAD(p); |
+ |
+ if (p->stopReading) |
+ { |
+ next->stopReading = True; |
+ return Event_Set(&next->canRead) == 0 ? SZ_OK : SZ_ERROR_THREAD; |
+ } |
+ |
+ { |
+ size_t size = p->mtCoder->blockSize; |
+ size_t destSize = p->outBufSize; |
+ |
+ RINOK(FullRead(p->mtCoder->inStream, p->inBuf, &size)); |
+ next->stopReading = *stop = (size != p->mtCoder->blockSize); |
+ if (Event_Set(&next->canRead) != 0) |
+ return SZ_ERROR_THREAD; |
+ |
+ RINOK(p->mtCoder->mtCallback->Code(p->mtCoder->mtCallback, p->index, |
+ p->outBuf, &destSize, p->inBuf, size, *stop)); |
+ |
+ MtProgress_Reinit(&p->mtCoder->mtProgress, p->index); |
+ |
+ if (Event_Wait(&p->canWrite) != 0) |
+ return SZ_ERROR_THREAD; |
+ if (p->stopWriting) |
+ return SZ_ERROR_FAIL; |
+ if (p->mtCoder->outStream->Write(p->mtCoder->outStream, p->outBuf, destSize) != destSize) |
+ return SZ_ERROR_WRITE; |
+ return Event_Set(&next->canWrite) == 0 ? SZ_OK : SZ_ERROR_THREAD; |
+ } |
+} |
+ |
+static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp) |
+{ |
+ CMtThread *p = (CMtThread *)pp; |
+ for (;;) |
+ { |
+ Bool stop; |
+ CMtThread *next = GET_NEXT_THREAD(p); |
+ SRes res = MtThread_Process(p, &stop); |
+ if (res != SZ_OK) |
+ { |
+ MtCoder_SetError(p->mtCoder, res); |
+ MtProgress_SetError(&p->mtCoder->mtProgress, res); |
+ next->stopReading = True; |
+ next->stopWriting = True; |
+ Event_Set(&next->canRead); |
+ Event_Set(&next->canWrite); |
+ return res; |
+ } |
+ if (stop) |
+ return 0; |
+ } |
+} |
+ |
+void MtCoder_Construct(CMtCoder* p) |
+{ |
+ unsigned i; |
+ p->alloc = 0; |
+ for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++) |
+ { |
+ CMtThread *t = &p->threads[i]; |
+ t->index = i; |
+ CMtThread_Construct(t, p); |
+ } |
+ CriticalSection_Init(&p->cs); |
+ CriticalSection_Init(&p->mtProgress.cs); |
+} |
+ |
+void MtCoder_Destruct(CMtCoder* p) |
+{ |
+ unsigned i; |
+ for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++) |
+ CMtThread_Destruct(&p->threads[i]); |
+ CriticalSection_Delete(&p->cs); |
+ CriticalSection_Delete(&p->mtProgress.cs); |
+} |
+ |
+SRes MtCoder_Code(CMtCoder *p) |
+{ |
+ unsigned i, numThreads = p->numThreads; |
+ SRes res = SZ_OK; |
+ p->res = SZ_OK; |
+ |
+ MtProgress_Init(&p->mtProgress, p->progress); |
+ |
+ for (i = 0; i < numThreads; i++) |
+ { |
+ RINOK(CMtThread_Prepare(&p->threads[i])); |
+ } |
+ |
+ for (i = 0; i < numThreads; i++) |
+ { |
+ CMtThread *t = &p->threads[i]; |
+ CLoopThread *lt = &t->thread; |
+ |
+ if (!Thread_WasCreated(<->thread)) |
+ { |
+ lt->func = ThreadFunc; |
+ lt->param = t; |
+ |
+ if (LoopThread_Create(lt) != SZ_OK) |
+ { |
+ res = SZ_ERROR_THREAD; |
+ break; |
+ } |
+ } |
+ } |
+ |
+ if (res == SZ_OK) |
+ { |
+ unsigned j; |
+ for (i = 0; i < numThreads; i++) |
+ { |
+ CMtThread *t = &p->threads[i]; |
+ if (LoopThread_StartSubThread(&t->thread) != SZ_OK) |
+ { |
+ res = SZ_ERROR_THREAD; |
+ p->threads[0].stopReading = True; |
+ break; |
+ } |
+ } |
+ |
+ Event_Set(&p->threads[0].canWrite); |
+ Event_Set(&p->threads[0].canRead); |
+ |
+ for (j = 0; j < i; j++) |
+ LoopThread_WaitSubThread(&p->threads[j].thread); |
+ } |
+ |
+ for (i = 0; i < numThreads; i++) |
+ CMtThread_CloseEvents(&p->threads[i]); |
+ return (res == SZ_OK) ? p->res : res; |
+} |
Property changes on: third_party\lzma_sdk\C\MtCoder.c |
___________________________________________________________________ |
Added: svn:executable |
+ * |
Added: svn:eol-style |
+ LF |