1370b324cSopenharmony_ci/* MtDec.c -- Multi-thread Decoder
2370b324cSopenharmony_ci2023-04-02 : Igor Pavlov : Public domain */
3370b324cSopenharmony_ci
4370b324cSopenharmony_ci#include "Precomp.h"
5370b324cSopenharmony_ci
6370b324cSopenharmony_ci// #define SHOW_DEBUG_INFO
7370b324cSopenharmony_ci
8370b324cSopenharmony_ci// #include <stdio.h>
9370b324cSopenharmony_ci#include <string.h>
10370b324cSopenharmony_ci
11370b324cSopenharmony_ci#ifdef SHOW_DEBUG_INFO
12370b324cSopenharmony_ci#include <stdio.h>
13370b324cSopenharmony_ci#endif
14370b324cSopenharmony_ci
15370b324cSopenharmony_ci#include "MtDec.h"
16370b324cSopenharmony_ci
17370b324cSopenharmony_ci#ifndef Z7_ST
18370b324cSopenharmony_ci
19370b324cSopenharmony_ci#ifdef SHOW_DEBUG_INFO
20370b324cSopenharmony_ci#define PRF(x) x
21370b324cSopenharmony_ci#else
22370b324cSopenharmony_ci#define PRF(x)
23370b324cSopenharmony_ci#endif
24370b324cSopenharmony_ci
25370b324cSopenharmony_ci#define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d))
26370b324cSopenharmony_ci
27370b324cSopenharmony_civoid MtProgress_Init(CMtProgress *p, ICompressProgressPtr progress)
28370b324cSopenharmony_ci{
29370b324cSopenharmony_ci  p->progress = progress;
30370b324cSopenharmony_ci  p->res = SZ_OK;
31370b324cSopenharmony_ci  p->totalInSize = 0;
32370b324cSopenharmony_ci  p->totalOutSize = 0;
33370b324cSopenharmony_ci}
34370b324cSopenharmony_ci
35370b324cSopenharmony_ci
36370b324cSopenharmony_ciSRes MtProgress_Progress_ST(CMtProgress *p)
37370b324cSopenharmony_ci{
38370b324cSopenharmony_ci  if (p->res == SZ_OK && p->progress)
39370b324cSopenharmony_ci    if (ICompressProgress_Progress(p->progress, p->totalInSize, p->totalOutSize) != SZ_OK)
40370b324cSopenharmony_ci      p->res = SZ_ERROR_PROGRESS;
41370b324cSopenharmony_ci  return p->res;
42370b324cSopenharmony_ci}
43370b324cSopenharmony_ci
44370b324cSopenharmony_ci
45370b324cSopenharmony_ciSRes MtProgress_ProgressAdd(CMtProgress *p, UInt64 inSize, UInt64 outSize)
46370b324cSopenharmony_ci{
47370b324cSopenharmony_ci  SRes res;
48370b324cSopenharmony_ci  CriticalSection_Enter(&p->cs);
49370b324cSopenharmony_ci
50370b324cSopenharmony_ci  p->totalInSize += inSize;
51370b324cSopenharmony_ci  p->totalOutSize += outSize;
52370b324cSopenharmony_ci  if (p->res == SZ_OK && p->progress)
53370b324cSopenharmony_ci    if (ICompressProgress_Progress(p->progress, p->totalInSize, p->totalOutSize) != SZ_OK)
54370b324cSopenharmony_ci      p->res = SZ_ERROR_PROGRESS;
55370b324cSopenharmony_ci  res = p->res;
56370b324cSopenharmony_ci
57370b324cSopenharmony_ci  CriticalSection_Leave(&p->cs);
58370b324cSopenharmony_ci  return res;
59370b324cSopenharmony_ci}
60370b324cSopenharmony_ci
61370b324cSopenharmony_ci
62370b324cSopenharmony_ciSRes MtProgress_GetError(CMtProgress *p)
63370b324cSopenharmony_ci{
64370b324cSopenharmony_ci  SRes res;
65370b324cSopenharmony_ci  CriticalSection_Enter(&p->cs);
66370b324cSopenharmony_ci  res = p->res;
67370b324cSopenharmony_ci  CriticalSection_Leave(&p->cs);
68370b324cSopenharmony_ci  return res;
69370b324cSopenharmony_ci}
70370b324cSopenharmony_ci
71370b324cSopenharmony_ci
72370b324cSopenharmony_civoid MtProgress_SetError(CMtProgress *p, SRes res)
73370b324cSopenharmony_ci{
74370b324cSopenharmony_ci  CriticalSection_Enter(&p->cs);
75370b324cSopenharmony_ci  if (p->res == SZ_OK)
76370b324cSopenharmony_ci    p->res = res;
77370b324cSopenharmony_ci  CriticalSection_Leave(&p->cs);
78370b324cSopenharmony_ci}
79370b324cSopenharmony_ci
80370b324cSopenharmony_ci
81370b324cSopenharmony_ci#define RINOK_THREAD(x) RINOK_WRes(x)
82370b324cSopenharmony_ci
83370b324cSopenharmony_ci
84370b324cSopenharmony_cistruct CMtDecBufLink_
85370b324cSopenharmony_ci{
86370b324cSopenharmony_ci  struct CMtDecBufLink_ *next;
87370b324cSopenharmony_ci  void *pad[3];
88370b324cSopenharmony_ci};
89370b324cSopenharmony_ci
90370b324cSopenharmony_citypedef struct CMtDecBufLink_ CMtDecBufLink;
91370b324cSopenharmony_ci
92370b324cSopenharmony_ci#define MTDEC__LINK_DATA_OFFSET sizeof(CMtDecBufLink)
93370b324cSopenharmony_ci#define MTDEC__DATA_PTR_FROM_LINK(link) ((Byte *)(link) + MTDEC__LINK_DATA_OFFSET)
94370b324cSopenharmony_ci
95370b324cSopenharmony_ci
96370b324cSopenharmony_ci
97370b324cSopenharmony_cistatic THREAD_FUNC_DECL MtDec_ThreadFunc(void *pp);
98370b324cSopenharmony_ci
99370b324cSopenharmony_ci
100370b324cSopenharmony_cistatic WRes MtDecThread_CreateEvents(CMtDecThread *t)
101370b324cSopenharmony_ci{
102370b324cSopenharmony_ci  WRes wres = AutoResetEvent_OptCreate_And_Reset(&t->canWrite);
103370b324cSopenharmony_ci  if (wres == 0)
104370b324cSopenharmony_ci  {
105370b324cSopenharmony_ci    wres = AutoResetEvent_OptCreate_And_Reset(&t->canRead);
106370b324cSopenharmony_ci    if (wres == 0)
107370b324cSopenharmony_ci      return SZ_OK;
108370b324cSopenharmony_ci  }
109370b324cSopenharmony_ci  return wres;
110370b324cSopenharmony_ci}
111370b324cSopenharmony_ci
112370b324cSopenharmony_ci
113370b324cSopenharmony_cistatic SRes MtDecThread_CreateAndStart(CMtDecThread *t)
114370b324cSopenharmony_ci{
115370b324cSopenharmony_ci  WRes wres = MtDecThread_CreateEvents(t);
116370b324cSopenharmony_ci  // wres = 17; // for test
117370b324cSopenharmony_ci  if (wres == 0)
118370b324cSopenharmony_ci  {
119370b324cSopenharmony_ci    if (Thread_WasCreated(&t->thread))
120370b324cSopenharmony_ci      return SZ_OK;
121370b324cSopenharmony_ci    wres = Thread_Create(&t->thread, MtDec_ThreadFunc, t);
122370b324cSopenharmony_ci    if (wres == 0)
123370b324cSopenharmony_ci      return SZ_OK;
124370b324cSopenharmony_ci  }
125370b324cSopenharmony_ci  return MY_SRes_HRESULT_FROM_WRes(wres);
126370b324cSopenharmony_ci}
127370b324cSopenharmony_ci
128370b324cSopenharmony_ci
129370b324cSopenharmony_civoid MtDecThread_FreeInBufs(CMtDecThread *t)
130370b324cSopenharmony_ci{
131370b324cSopenharmony_ci  if (t->inBuf)
132370b324cSopenharmony_ci  {
133370b324cSopenharmony_ci    void *link = t->inBuf;
134370b324cSopenharmony_ci    t->inBuf = NULL;
135370b324cSopenharmony_ci    do
136370b324cSopenharmony_ci    {
137370b324cSopenharmony_ci      void *next = ((CMtDecBufLink *)link)->next;
138370b324cSopenharmony_ci      ISzAlloc_Free(t->mtDec->alloc, link);
139370b324cSopenharmony_ci      link = next;
140370b324cSopenharmony_ci    }
141370b324cSopenharmony_ci    while (link);
142370b324cSopenharmony_ci  }
143370b324cSopenharmony_ci}
144370b324cSopenharmony_ci
145370b324cSopenharmony_ci
146370b324cSopenharmony_cistatic void MtDecThread_CloseThread(CMtDecThread *t)
147370b324cSopenharmony_ci{
148370b324cSopenharmony_ci  if (Thread_WasCreated(&t->thread))
149370b324cSopenharmony_ci  {
150370b324cSopenharmony_ci    Event_Set(&t->canWrite); /* we can disable it. There are no threads waiting canWrite in normal cases */
151370b324cSopenharmony_ci    Event_Set(&t->canRead);
152370b324cSopenharmony_ci    Thread_Wait_Close(&t->thread);
153370b324cSopenharmony_ci  }
154370b324cSopenharmony_ci
155370b324cSopenharmony_ci  Event_Close(&t->canRead);
156370b324cSopenharmony_ci  Event_Close(&t->canWrite);
157370b324cSopenharmony_ci}
158370b324cSopenharmony_ci
159370b324cSopenharmony_cistatic void MtDec_CloseThreads(CMtDec *p)
160370b324cSopenharmony_ci{
161370b324cSopenharmony_ci  unsigned i;
162370b324cSopenharmony_ci  for (i = 0; i < MTDEC_THREADS_MAX; i++)
163370b324cSopenharmony_ci    MtDecThread_CloseThread(&p->threads[i]);
164370b324cSopenharmony_ci}
165370b324cSopenharmony_ci
166370b324cSopenharmony_cistatic void MtDecThread_Destruct(CMtDecThread *t)
167370b324cSopenharmony_ci{
168370b324cSopenharmony_ci  MtDecThread_CloseThread(t);
169370b324cSopenharmony_ci  MtDecThread_FreeInBufs(t);
170370b324cSopenharmony_ci}
171370b324cSopenharmony_ci
172370b324cSopenharmony_ci
173370b324cSopenharmony_ci
174370b324cSopenharmony_cistatic SRes MtDec_GetError_Spec(CMtDec *p, UInt64 interruptIndex, BoolInt *wasInterrupted)
175370b324cSopenharmony_ci{
176370b324cSopenharmony_ci  SRes res;
177370b324cSopenharmony_ci  CriticalSection_Enter(&p->mtProgress.cs);
178370b324cSopenharmony_ci  *wasInterrupted = (p->needInterrupt && interruptIndex > p->interruptIndex);
179370b324cSopenharmony_ci  res = p->mtProgress.res;
180370b324cSopenharmony_ci  CriticalSection_Leave(&p->mtProgress.cs);
181370b324cSopenharmony_ci  return res;
182370b324cSopenharmony_ci}
183370b324cSopenharmony_ci
184370b324cSopenharmony_cistatic SRes MtDec_Progress_GetError_Spec(CMtDec *p, UInt64 inSize, UInt64 outSize, UInt64 interruptIndex, BoolInt *wasInterrupted)
185370b324cSopenharmony_ci{
186370b324cSopenharmony_ci  SRes res;
187370b324cSopenharmony_ci  CriticalSection_Enter(&p->mtProgress.cs);
188370b324cSopenharmony_ci
189370b324cSopenharmony_ci  p->mtProgress.totalInSize += inSize;
190370b324cSopenharmony_ci  p->mtProgress.totalOutSize += outSize;
191370b324cSopenharmony_ci  if (p->mtProgress.res == SZ_OK && p->mtProgress.progress)
192370b324cSopenharmony_ci    if (ICompressProgress_Progress(p->mtProgress.progress, p->mtProgress.totalInSize, p->mtProgress.totalOutSize) != SZ_OK)
193370b324cSopenharmony_ci      p->mtProgress.res = SZ_ERROR_PROGRESS;
194370b324cSopenharmony_ci
195370b324cSopenharmony_ci  *wasInterrupted = (p->needInterrupt && interruptIndex > p->interruptIndex);
196370b324cSopenharmony_ci  res = p->mtProgress.res;
197370b324cSopenharmony_ci
198370b324cSopenharmony_ci  CriticalSection_Leave(&p->mtProgress.cs);
199370b324cSopenharmony_ci
200370b324cSopenharmony_ci  return res;
201370b324cSopenharmony_ci}
202370b324cSopenharmony_ci
203370b324cSopenharmony_cistatic void MtDec_Interrupt(CMtDec *p, UInt64 interruptIndex)
204370b324cSopenharmony_ci{
205370b324cSopenharmony_ci  CriticalSection_Enter(&p->mtProgress.cs);
206370b324cSopenharmony_ci  if (!p->needInterrupt || interruptIndex < p->interruptIndex)
207370b324cSopenharmony_ci  {
208370b324cSopenharmony_ci    p->interruptIndex = interruptIndex;
209370b324cSopenharmony_ci    p->needInterrupt = True;
210370b324cSopenharmony_ci  }
211370b324cSopenharmony_ci  CriticalSection_Leave(&p->mtProgress.cs);
212370b324cSopenharmony_ci}
213370b324cSopenharmony_ci
214370b324cSopenharmony_ciByte *MtDec_GetCrossBuff(CMtDec *p)
215370b324cSopenharmony_ci{
216370b324cSopenharmony_ci  Byte *cr = p->crossBlock;
217370b324cSopenharmony_ci  if (!cr)
218370b324cSopenharmony_ci  {
219370b324cSopenharmony_ci    cr = (Byte *)ISzAlloc_Alloc(p->alloc, MTDEC__LINK_DATA_OFFSET + p->inBufSize);
220370b324cSopenharmony_ci    if (!cr)
221370b324cSopenharmony_ci      return NULL;
222370b324cSopenharmony_ci    p->crossBlock = cr;
223370b324cSopenharmony_ci  }
224370b324cSopenharmony_ci  return MTDEC__DATA_PTR_FROM_LINK(cr);
225370b324cSopenharmony_ci}
226370b324cSopenharmony_ci
227370b324cSopenharmony_ci
228370b324cSopenharmony_ci/*
229370b324cSopenharmony_ci  MtDec_ThreadFunc2() returns:
230370b324cSopenharmony_ci  0      - in all normal cases (even for stream error or memory allocation error)
231370b324cSopenharmony_ci  (!= 0) - WRes error return by system threading function
232370b324cSopenharmony_ci*/
233370b324cSopenharmony_ci
234370b324cSopenharmony_ci// #define MTDEC_ProgessStep (1 << 22)
235370b324cSopenharmony_ci#define MTDEC_ProgessStep (1 << 0)
236370b324cSopenharmony_ci
237370b324cSopenharmony_cistatic WRes MtDec_ThreadFunc2(CMtDecThread *t)
238370b324cSopenharmony_ci{
239370b324cSopenharmony_ci  CMtDec *p = t->mtDec;
240370b324cSopenharmony_ci
241370b324cSopenharmony_ci  PRF_STR_INT("MtDec_ThreadFunc2", t->index)
242370b324cSopenharmony_ci
243370b324cSopenharmony_ci  // SetThreadAffinityMask(GetCurrentThread(), 1 << t->index);
244370b324cSopenharmony_ci
245370b324cSopenharmony_ci  for (;;)
246370b324cSopenharmony_ci  {
247370b324cSopenharmony_ci    SRes res, codeRes;
248370b324cSopenharmony_ci    BoolInt wasInterrupted, isAllocError, overflow, finish;
249370b324cSopenharmony_ci    SRes threadingErrorSRes;
250370b324cSopenharmony_ci    BoolInt needCode, needWrite, needContinue;
251370b324cSopenharmony_ci
252370b324cSopenharmony_ci    size_t inDataSize_Start;
253370b324cSopenharmony_ci    UInt64 inDataSize;
254370b324cSopenharmony_ci    // UInt64 inDataSize_Full;
255370b324cSopenharmony_ci
256370b324cSopenharmony_ci    UInt64 blockIndex;
257370b324cSopenharmony_ci
258370b324cSopenharmony_ci    UInt64 inPrev = 0;
259370b324cSopenharmony_ci    UInt64 outPrev = 0;
260370b324cSopenharmony_ci    UInt64 inCodePos;
261370b324cSopenharmony_ci    UInt64 outCodePos;
262370b324cSopenharmony_ci
263370b324cSopenharmony_ci    Byte *afterEndData = NULL;
264370b324cSopenharmony_ci    size_t afterEndData_Size = 0;
265370b324cSopenharmony_ci    BoolInt afterEndData_IsCross = False;
266370b324cSopenharmony_ci
267370b324cSopenharmony_ci    BoolInt canCreateNewThread = False;
268370b324cSopenharmony_ci    // CMtDecCallbackInfo parse;
269370b324cSopenharmony_ci    CMtDecThread *nextThread;
270370b324cSopenharmony_ci
271370b324cSopenharmony_ci    PRF_STR_INT("=============== Event_Wait(&t->canRead)", t->index)
272370b324cSopenharmony_ci
273370b324cSopenharmony_ci    RINOK_THREAD(Event_Wait(&t->canRead))
274370b324cSopenharmony_ci    if (p->exitThread)
275370b324cSopenharmony_ci      return 0;
276370b324cSopenharmony_ci
277370b324cSopenharmony_ci    PRF_STR_INT("after Event_Wait(&t->canRead)", t->index)
278370b324cSopenharmony_ci
279370b324cSopenharmony_ci    // if (t->index == 3) return 19; // for test
280370b324cSopenharmony_ci
281370b324cSopenharmony_ci    blockIndex = p->blockIndex++;
282370b324cSopenharmony_ci
283370b324cSopenharmony_ci    // PRF(printf("\ncanRead\n"))
284370b324cSopenharmony_ci
285370b324cSopenharmony_ci    res = MtDec_Progress_GetError_Spec(p, 0, 0, blockIndex, &wasInterrupted);
286370b324cSopenharmony_ci
287370b324cSopenharmony_ci    finish = p->readWasFinished;
288370b324cSopenharmony_ci    needCode = False;
289370b324cSopenharmony_ci    needWrite = False;
290370b324cSopenharmony_ci    isAllocError = False;
291370b324cSopenharmony_ci    overflow = False;
292370b324cSopenharmony_ci
293370b324cSopenharmony_ci    inDataSize_Start = 0;
294370b324cSopenharmony_ci    inDataSize = 0;
295370b324cSopenharmony_ci    // inDataSize_Full = 0;
296370b324cSopenharmony_ci
297370b324cSopenharmony_ci    if (res == SZ_OK && !wasInterrupted)
298370b324cSopenharmony_ci    {
299370b324cSopenharmony_ci      // if (p->inStream)
300370b324cSopenharmony_ci      {
301370b324cSopenharmony_ci        CMtDecBufLink *prev = NULL;
302370b324cSopenharmony_ci        CMtDecBufLink *link = (CMtDecBufLink *)t->inBuf;
303370b324cSopenharmony_ci        size_t crossSize = p->crossEnd - p->crossStart;
304370b324cSopenharmony_ci
305370b324cSopenharmony_ci        PRF(printf("\ncrossSize = %d\n", crossSize));
306370b324cSopenharmony_ci
307370b324cSopenharmony_ci        for (;;)
308370b324cSopenharmony_ci        {
309370b324cSopenharmony_ci          if (!link)
310370b324cSopenharmony_ci          {
311370b324cSopenharmony_ci            link = (CMtDecBufLink *)ISzAlloc_Alloc(p->alloc, MTDEC__LINK_DATA_OFFSET + p->inBufSize);
312370b324cSopenharmony_ci            if (!link)
313370b324cSopenharmony_ci            {
314370b324cSopenharmony_ci              finish = True;
315370b324cSopenharmony_ci              // p->allocError_for_Read_BlockIndex = blockIndex;
316370b324cSopenharmony_ci              isAllocError = True;
317370b324cSopenharmony_ci              break;
318370b324cSopenharmony_ci            }
319370b324cSopenharmony_ci            link->next = NULL;
320370b324cSopenharmony_ci            if (prev)
321370b324cSopenharmony_ci            {
322370b324cSopenharmony_ci              // static unsigned g_num = 0;
323370b324cSopenharmony_ci              // printf("\n%6d : %x", ++g_num, (unsigned)(size_t)((Byte *)link - (Byte *)prev));
324370b324cSopenharmony_ci              prev->next = link;
325370b324cSopenharmony_ci            }
326370b324cSopenharmony_ci            else
327370b324cSopenharmony_ci              t->inBuf = (void *)link;
328370b324cSopenharmony_ci          }
329370b324cSopenharmony_ci
330370b324cSopenharmony_ci          {
331370b324cSopenharmony_ci            Byte *data = MTDEC__DATA_PTR_FROM_LINK(link);
332370b324cSopenharmony_ci            Byte *parseData = data;
333370b324cSopenharmony_ci            size_t size;
334370b324cSopenharmony_ci
335370b324cSopenharmony_ci            if (crossSize != 0)
336370b324cSopenharmony_ci            {
337370b324cSopenharmony_ci              inDataSize = crossSize;
338370b324cSopenharmony_ci              // inDataSize_Full = inDataSize;
339370b324cSopenharmony_ci              inDataSize_Start = crossSize;
340370b324cSopenharmony_ci              size = crossSize;
341370b324cSopenharmony_ci              parseData = MTDEC__DATA_PTR_FROM_LINK(p->crossBlock) + p->crossStart;
342370b324cSopenharmony_ci              PRF(printf("\ncross : crossStart = %7d  crossEnd = %7d finish = %1d",
343370b324cSopenharmony_ci                  (int)p->crossStart, (int)p->crossEnd, (int)finish));
344370b324cSopenharmony_ci            }
345370b324cSopenharmony_ci            else
346370b324cSopenharmony_ci            {
347370b324cSopenharmony_ci              size = p->inBufSize;
348370b324cSopenharmony_ci
349370b324cSopenharmony_ci              res = SeqInStream_ReadMax(p->inStream, data, &size);
350370b324cSopenharmony_ci
351370b324cSopenharmony_ci              // size = 10; // test
352370b324cSopenharmony_ci
353370b324cSopenharmony_ci              inDataSize += size;
354370b324cSopenharmony_ci              // inDataSize_Full = inDataSize;
355370b324cSopenharmony_ci              if (!prev)
356370b324cSopenharmony_ci                inDataSize_Start = size;
357370b324cSopenharmony_ci
358370b324cSopenharmony_ci              p->readProcessed += size;
359370b324cSopenharmony_ci              finish = (size != p->inBufSize);
360370b324cSopenharmony_ci              if (finish)
361370b324cSopenharmony_ci                p->readWasFinished = True;
362370b324cSopenharmony_ci
363370b324cSopenharmony_ci              // res = E_INVALIDARG; // test
364370b324cSopenharmony_ci
365370b324cSopenharmony_ci              if (res != SZ_OK)
366370b324cSopenharmony_ci              {
367370b324cSopenharmony_ci                // PRF(printf("\nRead error = %d\n", res))
368370b324cSopenharmony_ci                // we want to decode all data before error
369370b324cSopenharmony_ci                p->readRes = res;
370370b324cSopenharmony_ci                // p->readError_BlockIndex = blockIndex;
371370b324cSopenharmony_ci                p->readWasFinished = True;
372370b324cSopenharmony_ci                finish = True;
373370b324cSopenharmony_ci                res = SZ_OK;
374370b324cSopenharmony_ci                // break;
375370b324cSopenharmony_ci              }
376370b324cSopenharmony_ci
377370b324cSopenharmony_ci              if (inDataSize - inPrev >= MTDEC_ProgessStep)
378370b324cSopenharmony_ci              {
379370b324cSopenharmony_ci                res = MtDec_Progress_GetError_Spec(p, 0, 0, blockIndex, &wasInterrupted);
380370b324cSopenharmony_ci                if (res != SZ_OK || wasInterrupted)
381370b324cSopenharmony_ci                  break;
382370b324cSopenharmony_ci                inPrev = inDataSize;
383370b324cSopenharmony_ci              }
384370b324cSopenharmony_ci            }
385370b324cSopenharmony_ci
386370b324cSopenharmony_ci            {
387370b324cSopenharmony_ci              CMtDecCallbackInfo parse;
388370b324cSopenharmony_ci
389370b324cSopenharmony_ci              parse.startCall = (prev == NULL);
390370b324cSopenharmony_ci              parse.src = parseData;
391370b324cSopenharmony_ci              parse.srcSize = size;
392370b324cSopenharmony_ci              parse.srcFinished = finish;
393370b324cSopenharmony_ci              parse.canCreateNewThread = True;
394370b324cSopenharmony_ci
395370b324cSopenharmony_ci              PRF(printf("\nParse size = %d\n", (unsigned)size));
396370b324cSopenharmony_ci
397370b324cSopenharmony_ci              p->mtCallback->Parse(p->mtCallbackObject, t->index, &parse);
398370b324cSopenharmony_ci
399370b324cSopenharmony_ci              PRF(printf("   Parse processed = %d, state = %d \n", (unsigned)parse.srcSize, (unsigned)parse.state));
400370b324cSopenharmony_ci
401370b324cSopenharmony_ci              needWrite = True;
402370b324cSopenharmony_ci              canCreateNewThread = parse.canCreateNewThread;
403370b324cSopenharmony_ci
404370b324cSopenharmony_ci              // printf("\n\n%12I64u %12I64u", (UInt64)p->mtProgress.totalInSize, (UInt64)p->mtProgress.totalOutSize);
405370b324cSopenharmony_ci
406370b324cSopenharmony_ci              if (
407370b324cSopenharmony_ci                  // parseRes != SZ_OK ||
408370b324cSopenharmony_ci                  // inDataSize - (size - parse.srcSize) > p->inBlockMax
409370b324cSopenharmony_ci                  // ||
410370b324cSopenharmony_ci                  parse.state == MTDEC_PARSE_OVERFLOW
411370b324cSopenharmony_ci                  // || wasInterrupted
412370b324cSopenharmony_ci                  )
413370b324cSopenharmony_ci              {
414370b324cSopenharmony_ci                // Overflow or Parse error - switch from MT decoding to ST decoding
415370b324cSopenharmony_ci                finish = True;
416370b324cSopenharmony_ci                overflow = True;
417370b324cSopenharmony_ci
418370b324cSopenharmony_ci                {
419370b324cSopenharmony_ci                  PRF(printf("\n Overflow"));
420370b324cSopenharmony_ci                  // PRF(printf("\nisBlockFinished = %d", (unsigned)parse.blockWasFinished));
421370b324cSopenharmony_ci                  PRF(printf("\n inDataSize = %d", (unsigned)inDataSize));
422370b324cSopenharmony_ci                }
423370b324cSopenharmony_ci
424370b324cSopenharmony_ci                if (crossSize != 0)
425370b324cSopenharmony_ci                  memcpy(data, parseData, size);
426370b324cSopenharmony_ci                p->crossStart = 0;
427370b324cSopenharmony_ci                p->crossEnd = 0;
428370b324cSopenharmony_ci                break;
429370b324cSopenharmony_ci              }
430370b324cSopenharmony_ci
431370b324cSopenharmony_ci              if (crossSize != 0)
432370b324cSopenharmony_ci              {
433370b324cSopenharmony_ci                memcpy(data, parseData, parse.srcSize);
434370b324cSopenharmony_ci                p->crossStart += parse.srcSize;
435370b324cSopenharmony_ci              }
436370b324cSopenharmony_ci
437370b324cSopenharmony_ci              if (parse.state != MTDEC_PARSE_CONTINUE || finish)
438370b324cSopenharmony_ci              {
439370b324cSopenharmony_ci                // we don't need to parse in current thread anymore
440370b324cSopenharmony_ci
441370b324cSopenharmony_ci                if (parse.state == MTDEC_PARSE_END)
442370b324cSopenharmony_ci                  finish = True;
443370b324cSopenharmony_ci
444370b324cSopenharmony_ci                needCode = True;
445370b324cSopenharmony_ci                // p->crossFinished = finish;
446370b324cSopenharmony_ci
447370b324cSopenharmony_ci                if (parse.srcSize == size)
448370b324cSopenharmony_ci                {
449370b324cSopenharmony_ci                  // full parsed - no cross transfer
450370b324cSopenharmony_ci                  p->crossStart = 0;
451370b324cSopenharmony_ci                  p->crossEnd = 0;
452370b324cSopenharmony_ci                  break;
453370b324cSopenharmony_ci                }
454370b324cSopenharmony_ci
455370b324cSopenharmony_ci                if (parse.state == MTDEC_PARSE_END)
456370b324cSopenharmony_ci                {
457370b324cSopenharmony_ci                  afterEndData = parseData + parse.srcSize;
458370b324cSopenharmony_ci                  afterEndData_Size = size - parse.srcSize;
459370b324cSopenharmony_ci                  if (crossSize != 0)
460370b324cSopenharmony_ci                    afterEndData_IsCross = True;
461370b324cSopenharmony_ci                  // we reduce data size to required bytes (parsed only)
462370b324cSopenharmony_ci                  inDataSize -= afterEndData_Size;
463370b324cSopenharmony_ci                  if (!prev)
464370b324cSopenharmony_ci                    inDataSize_Start = parse.srcSize;
465370b324cSopenharmony_ci                  break;
466370b324cSopenharmony_ci                }
467370b324cSopenharmony_ci
468370b324cSopenharmony_ci                {
469370b324cSopenharmony_ci                  // partial parsed - need cross transfer
470370b324cSopenharmony_ci                  if (crossSize != 0)
471370b324cSopenharmony_ci                    inDataSize = parse.srcSize; // it's only parsed now
472370b324cSopenharmony_ci                  else
473370b324cSopenharmony_ci                  {
474370b324cSopenharmony_ci                    // partial parsed - is not in initial cross block - we need to copy new data to cross block
475370b324cSopenharmony_ci                    Byte *cr = MtDec_GetCrossBuff(p);
476370b324cSopenharmony_ci                    if (!cr)
477370b324cSopenharmony_ci                    {
478370b324cSopenharmony_ci                      {
479370b324cSopenharmony_ci                        PRF(printf("\ncross alloc error error\n"));
480370b324cSopenharmony_ci                        // res = SZ_ERROR_MEM;
481370b324cSopenharmony_ci                        finish = True;
482370b324cSopenharmony_ci                        // p->allocError_for_Read_BlockIndex = blockIndex;
483370b324cSopenharmony_ci                        isAllocError = True;
484370b324cSopenharmony_ci                        break;
485370b324cSopenharmony_ci                      }
486370b324cSopenharmony_ci                    }
487370b324cSopenharmony_ci
488370b324cSopenharmony_ci                    {
489370b324cSopenharmony_ci                      size_t crSize = size - parse.srcSize;
490370b324cSopenharmony_ci                      inDataSize -= crSize;
491370b324cSopenharmony_ci                      p->crossEnd = crSize;
492370b324cSopenharmony_ci                      p->crossStart = 0;
493370b324cSopenharmony_ci                      memcpy(cr, parseData + parse.srcSize, crSize);
494370b324cSopenharmony_ci                    }
495370b324cSopenharmony_ci                  }
496370b324cSopenharmony_ci
497370b324cSopenharmony_ci                  // inDataSize_Full = inDataSize;
498370b324cSopenharmony_ci                  if (!prev)
499370b324cSopenharmony_ci                    inDataSize_Start = parse.srcSize; // it's partial size (parsed only)
500370b324cSopenharmony_ci
501370b324cSopenharmony_ci                  finish = False;
502370b324cSopenharmony_ci                  break;
503370b324cSopenharmony_ci                }
504370b324cSopenharmony_ci              }
505370b324cSopenharmony_ci
506370b324cSopenharmony_ci              if (parse.srcSize != size)
507370b324cSopenharmony_ci              {
508370b324cSopenharmony_ci                res = SZ_ERROR_FAIL;
509370b324cSopenharmony_ci                PRF(printf("\nfinished error SZ_ERROR_FAIL = %d\n", res));
510370b324cSopenharmony_ci                break;
511370b324cSopenharmony_ci              }
512370b324cSopenharmony_ci            }
513370b324cSopenharmony_ci          }
514370b324cSopenharmony_ci
515370b324cSopenharmony_ci          prev = link;
516370b324cSopenharmony_ci          link = link->next;
517370b324cSopenharmony_ci
518370b324cSopenharmony_ci          if (crossSize != 0)
519370b324cSopenharmony_ci          {
520370b324cSopenharmony_ci            crossSize = 0;
521370b324cSopenharmony_ci            p->crossStart = 0;
522370b324cSopenharmony_ci            p->crossEnd = 0;
523370b324cSopenharmony_ci          }
524370b324cSopenharmony_ci        }
525370b324cSopenharmony_ci      }
526370b324cSopenharmony_ci
527370b324cSopenharmony_ci      if (res == SZ_OK)
528370b324cSopenharmony_ci        res = MtDec_GetError_Spec(p, blockIndex, &wasInterrupted);
529370b324cSopenharmony_ci    }
530370b324cSopenharmony_ci
531370b324cSopenharmony_ci    codeRes = SZ_OK;
532370b324cSopenharmony_ci
533370b324cSopenharmony_ci    if (res == SZ_OK && needCode && !wasInterrupted)
534370b324cSopenharmony_ci    {
535370b324cSopenharmony_ci      codeRes = p->mtCallback->PreCode(p->mtCallbackObject, t->index);
536370b324cSopenharmony_ci      if (codeRes != SZ_OK)
537370b324cSopenharmony_ci      {
538370b324cSopenharmony_ci        needCode = False;
539370b324cSopenharmony_ci        finish = True;
540370b324cSopenharmony_ci        // SZ_ERROR_MEM is expected error here.
541370b324cSopenharmony_ci        //   if (codeRes == SZ_ERROR_MEM) - we will try single-thread decoding later.
542370b324cSopenharmony_ci        //   if (codeRes != SZ_ERROR_MEM) - we can stop decoding or try single-thread decoding.
543370b324cSopenharmony_ci      }
544370b324cSopenharmony_ci    }
545370b324cSopenharmony_ci
546370b324cSopenharmony_ci    if (res != SZ_OK || wasInterrupted)
547370b324cSopenharmony_ci      finish = True;
548370b324cSopenharmony_ci
549370b324cSopenharmony_ci    nextThread = NULL;
550370b324cSopenharmony_ci    threadingErrorSRes = SZ_OK;
551370b324cSopenharmony_ci
552370b324cSopenharmony_ci    if (!finish)
553370b324cSopenharmony_ci    {
554370b324cSopenharmony_ci      if (p->numStartedThreads < p->numStartedThreads_Limit && canCreateNewThread)
555370b324cSopenharmony_ci      {
556370b324cSopenharmony_ci        SRes res2 = MtDecThread_CreateAndStart(&p->threads[p->numStartedThreads]);
557370b324cSopenharmony_ci        if (res2 == SZ_OK)
558370b324cSopenharmony_ci        {
559370b324cSopenharmony_ci          // if (p->numStartedThreads % 1000 == 0) PRF(printf("\n numStartedThreads=%d\n", p->numStartedThreads));
560370b324cSopenharmony_ci          p->numStartedThreads++;
561370b324cSopenharmony_ci        }
562370b324cSopenharmony_ci        else
563370b324cSopenharmony_ci        {
564370b324cSopenharmony_ci          PRF(printf("\nERROR: numStartedThreads=%d\n", p->numStartedThreads));
565370b324cSopenharmony_ci          if (p->numStartedThreads == 1)
566370b324cSopenharmony_ci          {
567370b324cSopenharmony_ci            // if only one thread is possible, we leave muti-threading code
568370b324cSopenharmony_ci            finish = True;
569370b324cSopenharmony_ci            needCode = False;
570370b324cSopenharmony_ci            threadingErrorSRes = res2;
571370b324cSopenharmony_ci          }
572370b324cSopenharmony_ci          else
573370b324cSopenharmony_ci            p->numStartedThreads_Limit = p->numStartedThreads;
574370b324cSopenharmony_ci        }
575370b324cSopenharmony_ci      }
576370b324cSopenharmony_ci
577370b324cSopenharmony_ci      if (!finish)
578370b324cSopenharmony_ci      {
579370b324cSopenharmony_ci        unsigned nextIndex = t->index + 1;
580370b324cSopenharmony_ci        nextThread = &p->threads[nextIndex >= p->numStartedThreads ? 0 : nextIndex];
581370b324cSopenharmony_ci        RINOK_THREAD(Event_Set(&nextThread->canRead))
582370b324cSopenharmony_ci        // We have started executing for new iteration (with next thread)
583370b324cSopenharmony_ci        // And that next thread now is responsible for possible exit from decoding (threading_code)
584370b324cSopenharmony_ci      }
585370b324cSopenharmony_ci    }
586370b324cSopenharmony_ci
587370b324cSopenharmony_ci    // each call of Event_Set(&nextThread->canRead) must be followed by call of Event_Set(&nextThread->canWrite)
588370b324cSopenharmony_ci    // if ( !finish ) we must call Event_Set(&nextThread->canWrite) in any case
589370b324cSopenharmony_ci    // if (  finish ) we switch to single-thread mode and there are 2 ways at the end of current iteration (current block):
590370b324cSopenharmony_ci    //   - if (needContinue) after Write(&needContinue), we restore decoding with new iteration
591370b324cSopenharmony_ci    //   - otherwise we stop decoding and exit from MtDec_ThreadFunc2()
592370b324cSopenharmony_ci
593370b324cSopenharmony_ci    // Don't change (finish) variable in the further code
594370b324cSopenharmony_ci
595370b324cSopenharmony_ci
596370b324cSopenharmony_ci    // ---------- CODE ----------
597370b324cSopenharmony_ci
598370b324cSopenharmony_ci    inPrev = 0;
599370b324cSopenharmony_ci    outPrev = 0;
600370b324cSopenharmony_ci    inCodePos = 0;
601370b324cSopenharmony_ci    outCodePos = 0;
602370b324cSopenharmony_ci
603370b324cSopenharmony_ci    if (res == SZ_OK && needCode && codeRes == SZ_OK)
604370b324cSopenharmony_ci    {
605370b324cSopenharmony_ci      BoolInt isStartBlock = True;
606370b324cSopenharmony_ci      CMtDecBufLink *link = (CMtDecBufLink *)t->inBuf;
607370b324cSopenharmony_ci
608370b324cSopenharmony_ci      for (;;)
609370b324cSopenharmony_ci      {
610370b324cSopenharmony_ci        size_t inSize;
611370b324cSopenharmony_ci        int stop;
612370b324cSopenharmony_ci
613370b324cSopenharmony_ci        if (isStartBlock)
614370b324cSopenharmony_ci          inSize = inDataSize_Start;
615370b324cSopenharmony_ci        else
616370b324cSopenharmony_ci        {
617370b324cSopenharmony_ci          UInt64 rem = inDataSize - inCodePos;
618370b324cSopenharmony_ci          inSize = p->inBufSize;
619370b324cSopenharmony_ci          if (inSize > rem)
620370b324cSopenharmony_ci            inSize = (size_t)rem;
621370b324cSopenharmony_ci        }
622370b324cSopenharmony_ci
623370b324cSopenharmony_ci        inCodePos += inSize;
624370b324cSopenharmony_ci        stop = True;
625370b324cSopenharmony_ci
626370b324cSopenharmony_ci        codeRes = p->mtCallback->Code(p->mtCallbackObject, t->index,
627370b324cSopenharmony_ci            (const Byte *)MTDEC__DATA_PTR_FROM_LINK(link), inSize,
628370b324cSopenharmony_ci            (inCodePos == inDataSize), // srcFinished
629370b324cSopenharmony_ci            &inCodePos, &outCodePos, &stop);
630370b324cSopenharmony_ci
631370b324cSopenharmony_ci        if (codeRes != SZ_OK)
632370b324cSopenharmony_ci        {
633370b324cSopenharmony_ci          PRF(printf("\nCode Interrupt error = %x\n", codeRes));
634370b324cSopenharmony_ci          // we interrupt only later blocks
635370b324cSopenharmony_ci          MtDec_Interrupt(p, blockIndex);
636370b324cSopenharmony_ci          break;
637370b324cSopenharmony_ci        }
638370b324cSopenharmony_ci
639370b324cSopenharmony_ci        if (stop || inCodePos == inDataSize)
640370b324cSopenharmony_ci          break;
641370b324cSopenharmony_ci
642370b324cSopenharmony_ci        {
643370b324cSopenharmony_ci          const UInt64 inDelta = inCodePos - inPrev;
644370b324cSopenharmony_ci          const UInt64 outDelta = outCodePos - outPrev;
645370b324cSopenharmony_ci          if (inDelta >= MTDEC_ProgessStep || outDelta >= MTDEC_ProgessStep)
646370b324cSopenharmony_ci          {
647370b324cSopenharmony_ci            // Sleep(1);
648370b324cSopenharmony_ci            res = MtDec_Progress_GetError_Spec(p, inDelta, outDelta, blockIndex, &wasInterrupted);
649370b324cSopenharmony_ci            if (res != SZ_OK || wasInterrupted)
650370b324cSopenharmony_ci              break;
651370b324cSopenharmony_ci            inPrev = inCodePos;
652370b324cSopenharmony_ci            outPrev = outCodePos;
653370b324cSopenharmony_ci          }
654370b324cSopenharmony_ci        }
655370b324cSopenharmony_ci
656370b324cSopenharmony_ci        link = link->next;
657370b324cSopenharmony_ci        isStartBlock = False;
658370b324cSopenharmony_ci      }
659370b324cSopenharmony_ci    }
660370b324cSopenharmony_ci
661370b324cSopenharmony_ci
662370b324cSopenharmony_ci    // ---------- WRITE ----------
663370b324cSopenharmony_ci
664370b324cSopenharmony_ci    RINOK_THREAD(Event_Wait(&t->canWrite))
665370b324cSopenharmony_ci
666370b324cSopenharmony_ci  {
667370b324cSopenharmony_ci    BoolInt isErrorMode = False;
668370b324cSopenharmony_ci    BoolInt canRecode = True;
669370b324cSopenharmony_ci    BoolInt needWriteToStream = needWrite;
670370b324cSopenharmony_ci
671370b324cSopenharmony_ci    if (p->exitThread) return 0; // it's never executed in normal cases
672370b324cSopenharmony_ci
673370b324cSopenharmony_ci    if (p->wasInterrupted)
674370b324cSopenharmony_ci      wasInterrupted = True;
675370b324cSopenharmony_ci    else
676370b324cSopenharmony_ci    {
677370b324cSopenharmony_ci      if (codeRes != SZ_OK) // || !needCode // check it !!!
678370b324cSopenharmony_ci      {
679370b324cSopenharmony_ci        p->wasInterrupted = True;
680370b324cSopenharmony_ci        p->codeRes = codeRes;
681370b324cSopenharmony_ci        if (codeRes == SZ_ERROR_MEM)
682370b324cSopenharmony_ci          isAllocError = True;
683370b324cSopenharmony_ci      }
684370b324cSopenharmony_ci
685370b324cSopenharmony_ci      if (threadingErrorSRes)
686370b324cSopenharmony_ci      {
687370b324cSopenharmony_ci        p->wasInterrupted = True;
688370b324cSopenharmony_ci        p->threadingErrorSRes = threadingErrorSRes;
689370b324cSopenharmony_ci        needWriteToStream = False;
690370b324cSopenharmony_ci      }
691370b324cSopenharmony_ci      if (isAllocError)
692370b324cSopenharmony_ci      {
693370b324cSopenharmony_ci        p->wasInterrupted = True;
694370b324cSopenharmony_ci        p->isAllocError = True;
695370b324cSopenharmony_ci        needWriteToStream = False;
696370b324cSopenharmony_ci      }
697370b324cSopenharmony_ci      if (overflow)
698370b324cSopenharmony_ci      {
699370b324cSopenharmony_ci        p->wasInterrupted = True;
700370b324cSopenharmony_ci        p->overflow = True;
701370b324cSopenharmony_ci        needWriteToStream = False;
702370b324cSopenharmony_ci      }
703370b324cSopenharmony_ci    }
704370b324cSopenharmony_ci
705370b324cSopenharmony_ci    if (needCode)
706370b324cSopenharmony_ci    {
707370b324cSopenharmony_ci      if (wasInterrupted)
708370b324cSopenharmony_ci      {
709370b324cSopenharmony_ci        inCodePos = 0;
710370b324cSopenharmony_ci        outCodePos = 0;
711370b324cSopenharmony_ci      }
712370b324cSopenharmony_ci      {
713370b324cSopenharmony_ci        const UInt64 inDelta = inCodePos - inPrev;
714370b324cSopenharmony_ci        const UInt64 outDelta = outCodePos - outPrev;
715370b324cSopenharmony_ci        // if (inDelta != 0 || outDelta != 0)
716370b324cSopenharmony_ci        res = MtProgress_ProgressAdd(&p->mtProgress, inDelta, outDelta);
717370b324cSopenharmony_ci      }
718370b324cSopenharmony_ci    }
719370b324cSopenharmony_ci
720370b324cSopenharmony_ci    needContinue = (!finish);
721370b324cSopenharmony_ci
722370b324cSopenharmony_ci    // if (res == SZ_OK && needWrite && !wasInterrupted)
723370b324cSopenharmony_ci    if (needWrite)
724370b324cSopenharmony_ci    {
725370b324cSopenharmony_ci      // p->inProcessed += inCodePos;
726370b324cSopenharmony_ci
727370b324cSopenharmony_ci      PRF(printf("\n--Write afterSize = %d\n", (unsigned)afterEndData_Size));
728370b324cSopenharmony_ci
729370b324cSopenharmony_ci      res = p->mtCallback->Write(p->mtCallbackObject, t->index,
730370b324cSopenharmony_ci          res == SZ_OK && needWriteToStream && !wasInterrupted, // needWrite
731370b324cSopenharmony_ci          afterEndData, afterEndData_Size, afterEndData_IsCross,
732370b324cSopenharmony_ci          &needContinue,
733370b324cSopenharmony_ci          &canRecode);
734370b324cSopenharmony_ci
735370b324cSopenharmony_ci      // res = SZ_ERROR_FAIL; // for test
736370b324cSopenharmony_ci
737370b324cSopenharmony_ci      PRF(printf("\nAfter Write needContinue = %d\n", (unsigned)needContinue));
738370b324cSopenharmony_ci      PRF(printf("\nprocessed = %d\n", (unsigned)p->inProcessed));
739370b324cSopenharmony_ci
740370b324cSopenharmony_ci      if (res != SZ_OK)
741370b324cSopenharmony_ci      {
742370b324cSopenharmony_ci        PRF(printf("\nWrite error = %d\n", res));
743370b324cSopenharmony_ci        isErrorMode = True;
744370b324cSopenharmony_ci        p->wasInterrupted = True;
745370b324cSopenharmony_ci      }
746370b324cSopenharmony_ci      if (res != SZ_OK
747370b324cSopenharmony_ci          || (!needContinue && !finish))
748370b324cSopenharmony_ci      {
749370b324cSopenharmony_ci        PRF(printf("\nWrite Interrupt error = %x\n", res));
750370b324cSopenharmony_ci        MtDec_Interrupt(p, blockIndex);
751370b324cSopenharmony_ci      }
752370b324cSopenharmony_ci    }
753370b324cSopenharmony_ci
754370b324cSopenharmony_ci    if (canRecode)
755370b324cSopenharmony_ci    if (!needCode
756370b324cSopenharmony_ci        || res != SZ_OK
757370b324cSopenharmony_ci        || p->wasInterrupted
758370b324cSopenharmony_ci        || codeRes != SZ_OK
759370b324cSopenharmony_ci        || wasInterrupted
760370b324cSopenharmony_ci        || p->numFilledThreads != 0
761370b324cSopenharmony_ci        || isErrorMode)
762370b324cSopenharmony_ci    {
763370b324cSopenharmony_ci      if (p->numFilledThreads == 0)
764370b324cSopenharmony_ci        p->filledThreadStart = t->index;
765370b324cSopenharmony_ci      if (inDataSize != 0 || !finish)
766370b324cSopenharmony_ci      {
767370b324cSopenharmony_ci        t->inDataSize_Start = inDataSize_Start;
768370b324cSopenharmony_ci        t->inDataSize = inDataSize;
769370b324cSopenharmony_ci        p->numFilledThreads++;
770370b324cSopenharmony_ci      }
771370b324cSopenharmony_ci      PRF(printf("\np->numFilledThreads = %d\n", p->numFilledThreads));
772370b324cSopenharmony_ci      PRF(printf("p->filledThreadStart = %d\n", p->filledThreadStart));
773370b324cSopenharmony_ci    }
774370b324cSopenharmony_ci
775370b324cSopenharmony_ci    if (!finish)
776370b324cSopenharmony_ci    {
777370b324cSopenharmony_ci      RINOK_THREAD(Event_Set(&nextThread->canWrite))
778370b324cSopenharmony_ci    }
779370b324cSopenharmony_ci    else
780370b324cSopenharmony_ci    {
781370b324cSopenharmony_ci      if (needContinue)
782370b324cSopenharmony_ci      {
783370b324cSopenharmony_ci        // we restore decoding with new iteration
784370b324cSopenharmony_ci        RINOK_THREAD(Event_Set(&p->threads[0].canWrite))
785370b324cSopenharmony_ci      }
786370b324cSopenharmony_ci      else
787370b324cSopenharmony_ci      {
788370b324cSopenharmony_ci        // we exit from decoding
789370b324cSopenharmony_ci        if (t->index == 0)
790370b324cSopenharmony_ci          return SZ_OK;
791370b324cSopenharmony_ci        p->exitThread = True;
792370b324cSopenharmony_ci      }
793370b324cSopenharmony_ci      RINOK_THREAD(Event_Set(&p->threads[0].canRead))
794370b324cSopenharmony_ci    }
795370b324cSopenharmony_ci  }
796370b324cSopenharmony_ci  }
797370b324cSopenharmony_ci}
798370b324cSopenharmony_ci
799370b324cSopenharmony_ci#ifdef _WIN32
800370b324cSopenharmony_ci#define USE_ALLOCA
801370b324cSopenharmony_ci#endif
802370b324cSopenharmony_ci
803370b324cSopenharmony_ci#ifdef USE_ALLOCA
804370b324cSopenharmony_ci#ifdef _WIN32
805370b324cSopenharmony_ci#include <malloc.h>
806370b324cSopenharmony_ci#else
807370b324cSopenharmony_ci#include <stdlib.h>
808370b324cSopenharmony_ci#endif
809370b324cSopenharmony_ci#endif
810370b324cSopenharmony_ci
811370b324cSopenharmony_ci
812370b324cSopenharmony_cistatic THREAD_FUNC_DECL MtDec_ThreadFunc1(void *pp)
813370b324cSopenharmony_ci{
814370b324cSopenharmony_ci  WRes res;
815370b324cSopenharmony_ci
816370b324cSopenharmony_ci  CMtDecThread *t = (CMtDecThread *)pp;
817370b324cSopenharmony_ci  CMtDec *p;
818370b324cSopenharmony_ci
819370b324cSopenharmony_ci  // fprintf(stdout, "\n%d = %p\n", t->index, &t);
820370b324cSopenharmony_ci
821370b324cSopenharmony_ci  res = MtDec_ThreadFunc2(t);
822370b324cSopenharmony_ci  p = t->mtDec;
823370b324cSopenharmony_ci  if (res == 0)
824370b324cSopenharmony_ci    return (THREAD_FUNC_RET_TYPE)(UINT_PTR)p->exitThreadWRes;
825370b324cSopenharmony_ci  {
826370b324cSopenharmony_ci    // it's unexpected situation for some threading function error
827370b324cSopenharmony_ci    if (p->exitThreadWRes == 0)
828370b324cSopenharmony_ci      p->exitThreadWRes = res;
829370b324cSopenharmony_ci    PRF(printf("\nthread exit error = %d\n", res));
830370b324cSopenharmony_ci    p->exitThread = True;
831370b324cSopenharmony_ci    Event_Set(&p->threads[0].canRead);
832370b324cSopenharmony_ci    Event_Set(&p->threads[0].canWrite);
833370b324cSopenharmony_ci    MtProgress_SetError(&p->mtProgress, MY_SRes_HRESULT_FROM_WRes(res));
834370b324cSopenharmony_ci  }
835370b324cSopenharmony_ci  return (THREAD_FUNC_RET_TYPE)(UINT_PTR)res;
836370b324cSopenharmony_ci}
837370b324cSopenharmony_ci
838370b324cSopenharmony_cistatic Z7_NO_INLINE THREAD_FUNC_DECL MtDec_ThreadFunc(void *pp)
839370b324cSopenharmony_ci{
840370b324cSopenharmony_ci  #ifdef USE_ALLOCA
841370b324cSopenharmony_ci  CMtDecThread *t = (CMtDecThread *)pp;
842370b324cSopenharmony_ci  // fprintf(stderr, "\n%d = %p - before", t->index, &t);
843370b324cSopenharmony_ci  t->allocaPtr = alloca(t->index * 128);
844370b324cSopenharmony_ci  #endif
845370b324cSopenharmony_ci  return MtDec_ThreadFunc1(pp);
846370b324cSopenharmony_ci}
847370b324cSopenharmony_ci
848370b324cSopenharmony_ci
849370b324cSopenharmony_ciint MtDec_PrepareRead(CMtDec *p)
850370b324cSopenharmony_ci{
851370b324cSopenharmony_ci  if (p->crossBlock && p->crossStart == p->crossEnd)
852370b324cSopenharmony_ci  {
853370b324cSopenharmony_ci    ISzAlloc_Free(p->alloc, p->crossBlock);
854370b324cSopenharmony_ci    p->crossBlock = NULL;
855370b324cSopenharmony_ci  }
856370b324cSopenharmony_ci
857370b324cSopenharmony_ci  {
858370b324cSopenharmony_ci    unsigned i;
859370b324cSopenharmony_ci    for (i = 0; i < MTDEC_THREADS_MAX; i++)
860370b324cSopenharmony_ci      if (i > p->numStartedThreads
861370b324cSopenharmony_ci          || p->numFilledThreads <=
862370b324cSopenharmony_ci            (i >= p->filledThreadStart ?
863370b324cSopenharmony_ci              i - p->filledThreadStart :
864370b324cSopenharmony_ci              i + p->numStartedThreads - p->filledThreadStart))
865370b324cSopenharmony_ci        MtDecThread_FreeInBufs(&p->threads[i]);
866370b324cSopenharmony_ci  }
867370b324cSopenharmony_ci
868370b324cSopenharmony_ci  return (p->numFilledThreads != 0) || (p->crossStart != p->crossEnd);
869370b324cSopenharmony_ci}
870370b324cSopenharmony_ci
871370b324cSopenharmony_ci
872370b324cSopenharmony_ciconst Byte *MtDec_Read(CMtDec *p, size_t *inLim)
873370b324cSopenharmony_ci{
874370b324cSopenharmony_ci  while (p->numFilledThreads != 0)
875370b324cSopenharmony_ci  {
876370b324cSopenharmony_ci    CMtDecThread *t = &p->threads[p->filledThreadStart];
877370b324cSopenharmony_ci
878370b324cSopenharmony_ci    if (*inLim != 0)
879370b324cSopenharmony_ci    {
880370b324cSopenharmony_ci      {
881370b324cSopenharmony_ci        void *link = t->inBuf;
882370b324cSopenharmony_ci        void *next = ((CMtDecBufLink *)link)->next;
883370b324cSopenharmony_ci        ISzAlloc_Free(p->alloc, link);
884370b324cSopenharmony_ci        t->inBuf = next;
885370b324cSopenharmony_ci      }
886370b324cSopenharmony_ci
887370b324cSopenharmony_ci      if (t->inDataSize == 0)
888370b324cSopenharmony_ci      {
889370b324cSopenharmony_ci        MtDecThread_FreeInBufs(t);
890370b324cSopenharmony_ci        if (--p->numFilledThreads == 0)
891370b324cSopenharmony_ci          break;
892370b324cSopenharmony_ci        if (++p->filledThreadStart == p->numStartedThreads)
893370b324cSopenharmony_ci          p->filledThreadStart = 0;
894370b324cSopenharmony_ci        t = &p->threads[p->filledThreadStart];
895370b324cSopenharmony_ci      }
896370b324cSopenharmony_ci    }
897370b324cSopenharmony_ci
898370b324cSopenharmony_ci    {
899370b324cSopenharmony_ci      size_t lim = t->inDataSize_Start;
900370b324cSopenharmony_ci      if (lim != 0)
901370b324cSopenharmony_ci        t->inDataSize_Start = 0;
902370b324cSopenharmony_ci      else
903370b324cSopenharmony_ci      {
904370b324cSopenharmony_ci        UInt64 rem = t->inDataSize;
905370b324cSopenharmony_ci        lim = p->inBufSize;
906370b324cSopenharmony_ci        if (lim > rem)
907370b324cSopenharmony_ci          lim = (size_t)rem;
908370b324cSopenharmony_ci      }
909370b324cSopenharmony_ci      t->inDataSize -= lim;
910370b324cSopenharmony_ci      *inLim = lim;
911370b324cSopenharmony_ci      return (const Byte *)MTDEC__DATA_PTR_FROM_LINK(t->inBuf);
912370b324cSopenharmony_ci    }
913370b324cSopenharmony_ci  }
914370b324cSopenharmony_ci
915370b324cSopenharmony_ci  {
916370b324cSopenharmony_ci    size_t crossSize = p->crossEnd - p->crossStart;
917370b324cSopenharmony_ci    if (crossSize != 0)
918370b324cSopenharmony_ci    {
919370b324cSopenharmony_ci      const Byte *data = MTDEC__DATA_PTR_FROM_LINK(p->crossBlock) + p->crossStart;
920370b324cSopenharmony_ci      *inLim = crossSize;
921370b324cSopenharmony_ci      p->crossStart = 0;
922370b324cSopenharmony_ci      p->crossEnd = 0;
923370b324cSopenharmony_ci      return data;
924370b324cSopenharmony_ci    }
925370b324cSopenharmony_ci    *inLim = 0;
926370b324cSopenharmony_ci    if (p->crossBlock)
927370b324cSopenharmony_ci    {
928370b324cSopenharmony_ci      ISzAlloc_Free(p->alloc, p->crossBlock);
929370b324cSopenharmony_ci      p->crossBlock = NULL;
930370b324cSopenharmony_ci    }
931370b324cSopenharmony_ci    return NULL;
932370b324cSopenharmony_ci  }
933370b324cSopenharmony_ci}
934370b324cSopenharmony_ci
935370b324cSopenharmony_ci
936370b324cSopenharmony_civoid MtDec_Construct(CMtDec *p)
937370b324cSopenharmony_ci{
938370b324cSopenharmony_ci  unsigned i;
939370b324cSopenharmony_ci
940370b324cSopenharmony_ci  p->inBufSize = (size_t)1 << 18;
941370b324cSopenharmony_ci
942370b324cSopenharmony_ci  p->numThreadsMax = 0;
943370b324cSopenharmony_ci
944370b324cSopenharmony_ci  p->inStream = NULL;
945370b324cSopenharmony_ci
946370b324cSopenharmony_ci  // p->inData = NULL;
947370b324cSopenharmony_ci  // p->inDataSize = 0;
948370b324cSopenharmony_ci
949370b324cSopenharmony_ci  p->crossBlock = NULL;
950370b324cSopenharmony_ci  p->crossStart = 0;
951370b324cSopenharmony_ci  p->crossEnd = 0;
952370b324cSopenharmony_ci
953370b324cSopenharmony_ci  p->numFilledThreads = 0;
954370b324cSopenharmony_ci
955370b324cSopenharmony_ci  p->progress = NULL;
956370b324cSopenharmony_ci  p->alloc = NULL;
957370b324cSopenharmony_ci
958370b324cSopenharmony_ci  p->mtCallback = NULL;
959370b324cSopenharmony_ci  p->mtCallbackObject = NULL;
960370b324cSopenharmony_ci
961370b324cSopenharmony_ci  p->allocatedBufsSize = 0;
962370b324cSopenharmony_ci
963370b324cSopenharmony_ci  for (i = 0; i < MTDEC_THREADS_MAX; i++)
964370b324cSopenharmony_ci  {
965370b324cSopenharmony_ci    CMtDecThread *t = &p->threads[i];
966370b324cSopenharmony_ci    t->mtDec = p;
967370b324cSopenharmony_ci    t->index = i;
968370b324cSopenharmony_ci    t->inBuf = NULL;
969370b324cSopenharmony_ci    Event_Construct(&t->canRead);
970370b324cSopenharmony_ci    Event_Construct(&t->canWrite);
971370b324cSopenharmony_ci    Thread_CONSTRUCT(&t->thread)
972370b324cSopenharmony_ci  }
973370b324cSopenharmony_ci
974370b324cSopenharmony_ci  // Event_Construct(&p->finishedEvent);
975370b324cSopenharmony_ci
976370b324cSopenharmony_ci  CriticalSection_Init(&p->mtProgress.cs);
977370b324cSopenharmony_ci}
978370b324cSopenharmony_ci
979370b324cSopenharmony_ci
980370b324cSopenharmony_cistatic void MtDec_Free(CMtDec *p)
981370b324cSopenharmony_ci{
982370b324cSopenharmony_ci  unsigned i;
983370b324cSopenharmony_ci
984370b324cSopenharmony_ci  p->exitThread = True;
985370b324cSopenharmony_ci
986370b324cSopenharmony_ci  for (i = 0; i < MTDEC_THREADS_MAX; i++)
987370b324cSopenharmony_ci    MtDecThread_Destruct(&p->threads[i]);
988370b324cSopenharmony_ci
989370b324cSopenharmony_ci  // Event_Close(&p->finishedEvent);
990370b324cSopenharmony_ci
991370b324cSopenharmony_ci  if (p->crossBlock)
992370b324cSopenharmony_ci  {
993370b324cSopenharmony_ci    ISzAlloc_Free(p->alloc, p->crossBlock);
994370b324cSopenharmony_ci    p->crossBlock = NULL;
995370b324cSopenharmony_ci  }
996370b324cSopenharmony_ci}
997370b324cSopenharmony_ci
998370b324cSopenharmony_ci
999370b324cSopenharmony_civoid MtDec_Destruct(CMtDec *p)
1000370b324cSopenharmony_ci{
1001370b324cSopenharmony_ci  MtDec_Free(p);
1002370b324cSopenharmony_ci
1003370b324cSopenharmony_ci  CriticalSection_Delete(&p->mtProgress.cs);
1004370b324cSopenharmony_ci}
1005370b324cSopenharmony_ci
1006370b324cSopenharmony_ci
1007370b324cSopenharmony_ciSRes MtDec_Code(CMtDec *p)
1008370b324cSopenharmony_ci{
1009370b324cSopenharmony_ci  unsigned i;
1010370b324cSopenharmony_ci
1011370b324cSopenharmony_ci  p->inProcessed = 0;
1012370b324cSopenharmony_ci
1013370b324cSopenharmony_ci  p->blockIndex = 1; // it must be larger than not_defined index (0)
1014370b324cSopenharmony_ci  p->isAllocError = False;
1015370b324cSopenharmony_ci  p->overflow = False;
1016370b324cSopenharmony_ci  p->threadingErrorSRes = SZ_OK;
1017370b324cSopenharmony_ci
1018370b324cSopenharmony_ci  p->needContinue = True;
1019370b324cSopenharmony_ci
1020370b324cSopenharmony_ci  p->readWasFinished = False;
1021370b324cSopenharmony_ci  p->needInterrupt = False;
1022370b324cSopenharmony_ci  p->interruptIndex = (UInt64)(Int64)-1;
1023370b324cSopenharmony_ci
1024370b324cSopenharmony_ci  p->readProcessed = 0;
1025370b324cSopenharmony_ci  p->readRes = SZ_OK;
1026370b324cSopenharmony_ci  p->codeRes = SZ_OK;
1027370b324cSopenharmony_ci  p->wasInterrupted = False;
1028370b324cSopenharmony_ci
1029370b324cSopenharmony_ci  p->crossStart = 0;
1030370b324cSopenharmony_ci  p->crossEnd = 0;
1031370b324cSopenharmony_ci
1032370b324cSopenharmony_ci  p->filledThreadStart = 0;
1033370b324cSopenharmony_ci  p->numFilledThreads = 0;
1034370b324cSopenharmony_ci
1035370b324cSopenharmony_ci  {
1036370b324cSopenharmony_ci    unsigned numThreads = p->numThreadsMax;
1037370b324cSopenharmony_ci    if (numThreads > MTDEC_THREADS_MAX)
1038370b324cSopenharmony_ci      numThreads = MTDEC_THREADS_MAX;
1039370b324cSopenharmony_ci    p->numStartedThreads_Limit = numThreads;
1040370b324cSopenharmony_ci    p->numStartedThreads = 0;
1041370b324cSopenharmony_ci  }
1042370b324cSopenharmony_ci
1043370b324cSopenharmony_ci  if (p->inBufSize != p->allocatedBufsSize)
1044370b324cSopenharmony_ci  {
1045370b324cSopenharmony_ci    for (i = 0; i < MTDEC_THREADS_MAX; i++)
1046370b324cSopenharmony_ci    {
1047370b324cSopenharmony_ci      CMtDecThread *t = &p->threads[i];
1048370b324cSopenharmony_ci      if (t->inBuf)
1049370b324cSopenharmony_ci        MtDecThread_FreeInBufs(t);
1050370b324cSopenharmony_ci    }
1051370b324cSopenharmony_ci    if (p->crossBlock)
1052370b324cSopenharmony_ci    {
1053370b324cSopenharmony_ci      ISzAlloc_Free(p->alloc, p->crossBlock);
1054370b324cSopenharmony_ci      p->crossBlock = NULL;
1055370b324cSopenharmony_ci    }
1056370b324cSopenharmony_ci
1057370b324cSopenharmony_ci    p->allocatedBufsSize = p->inBufSize;
1058370b324cSopenharmony_ci  }
1059370b324cSopenharmony_ci
1060370b324cSopenharmony_ci  MtProgress_Init(&p->mtProgress, p->progress);
1061370b324cSopenharmony_ci
1062370b324cSopenharmony_ci  // RINOK_THREAD(AutoResetEvent_OptCreate_And_Reset(&p->finishedEvent))
1063370b324cSopenharmony_ci  p->exitThread = False;
1064370b324cSopenharmony_ci  p->exitThreadWRes = 0;
1065370b324cSopenharmony_ci
1066370b324cSopenharmony_ci  {
1067370b324cSopenharmony_ci    WRes wres;
1068370b324cSopenharmony_ci    SRes sres;
1069370b324cSopenharmony_ci    CMtDecThread *nextThread = &p->threads[p->numStartedThreads++];
1070370b324cSopenharmony_ci    // wres = MtDecThread_CreateAndStart(nextThread);
1071370b324cSopenharmony_ci    wres = MtDecThread_CreateEvents(nextThread);
1072370b324cSopenharmony_ci    if (wres == 0) { wres = Event_Set(&nextThread->canWrite);
1073370b324cSopenharmony_ci    if (wres == 0) { wres = Event_Set(&nextThread->canRead);
1074370b324cSopenharmony_ci    if (wres == 0) { THREAD_FUNC_RET_TYPE res = MtDec_ThreadFunc(nextThread);
1075370b324cSopenharmony_ci    wres = (WRes)(UINT_PTR)res;
1076370b324cSopenharmony_ci    if (wres != 0)
1077370b324cSopenharmony_ci    {
1078370b324cSopenharmony_ci      p->needContinue = False;
1079370b324cSopenharmony_ci      MtDec_CloseThreads(p);
1080370b324cSopenharmony_ci    }}}}
1081370b324cSopenharmony_ci
1082370b324cSopenharmony_ci    // wres = 17; // for test
1083370b324cSopenharmony_ci    // wres = Event_Wait(&p->finishedEvent);
1084370b324cSopenharmony_ci
1085370b324cSopenharmony_ci    sres = MY_SRes_HRESULT_FROM_WRes(wres);
1086370b324cSopenharmony_ci
1087370b324cSopenharmony_ci    if (sres != 0)
1088370b324cSopenharmony_ci      p->threadingErrorSRes = sres;
1089370b324cSopenharmony_ci
1090370b324cSopenharmony_ci    if (
1091370b324cSopenharmony_ci        // wres == 0
1092370b324cSopenharmony_ci        // wres != 0
1093370b324cSopenharmony_ci        // || p->mtc.codeRes == SZ_ERROR_MEM
1094370b324cSopenharmony_ci        p->isAllocError
1095370b324cSopenharmony_ci        || p->threadingErrorSRes != SZ_OK
1096370b324cSopenharmony_ci        || p->overflow)
1097370b324cSopenharmony_ci    {
1098370b324cSopenharmony_ci      // p->needContinue = True;
1099370b324cSopenharmony_ci    }
1100370b324cSopenharmony_ci    else
1101370b324cSopenharmony_ci      p->needContinue = False;
1102370b324cSopenharmony_ci
1103370b324cSopenharmony_ci    if (p->needContinue)
1104370b324cSopenharmony_ci      return SZ_OK;
1105370b324cSopenharmony_ci
1106370b324cSopenharmony_ci    // if (sres != SZ_OK)
1107370b324cSopenharmony_ci    return sres;
1108370b324cSopenharmony_ci    // return SZ_ERROR_FAIL;
1109370b324cSopenharmony_ci  }
1110370b324cSopenharmony_ci}
1111370b324cSopenharmony_ci
1112370b324cSopenharmony_ci#endif
1113370b324cSopenharmony_ci
1114370b324cSopenharmony_ci#undef PRF
1115