Lightly modified commit of lzma sdk version 9.20.

The only change from stock lzma sdk is the removal of two
.exe files, which we don't need.

Change-Id: I46287cbc416161e93b449761ebe531acd758cf95
diff --git a/C/MtCoder.c b/C/MtCoder.c
new file mode 100755
index 0000000..9f0d268
--- /dev/null
+++ b/C/MtCoder.c
@@ -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(&lt->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;

+}