Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

329 lines
7.8 KiB

  1. /* MtCoder.c -- Multi-thread Coder
  2. 2010-09-24 : Igor Pavlov : Public domain */
  3. #include "Precomp.h"
  4. #include <stdio.h>
  5. #include "MtCoder.h"
  6. void LoopThread_Construct(CLoopThread *p)
  7. {
  8. Thread_Construct(&p->thread);
  9. Event_Construct(&p->startEvent);
  10. Event_Construct(&p->finishedEvent);
  11. }
  12. void LoopThread_Close(CLoopThread *p)
  13. {
  14. Thread_Close(&p->thread);
  15. Event_Close(&p->startEvent);
  16. Event_Close(&p->finishedEvent);
  17. }
  18. static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE LoopThreadFunc(void *pp)
  19. {
  20. CLoopThread *p = (CLoopThread *)pp;
  21. for (;;)
  22. {
  23. if (Event_Wait(&p->startEvent) != 0)
  24. return SZ_ERROR_THREAD;
  25. if (p->stop)
  26. return 0;
  27. p->res = p->func(p->param);
  28. if (Event_Set(&p->finishedEvent) != 0)
  29. return SZ_ERROR_THREAD;
  30. }
  31. }
  32. WRes LoopThread_Create(CLoopThread *p)
  33. {
  34. p->stop = 0;
  35. RINOK(AutoResetEvent_CreateNotSignaled(&p->startEvent));
  36. RINOK(AutoResetEvent_CreateNotSignaled(&p->finishedEvent));
  37. return Thread_Create(&p->thread, LoopThreadFunc, p);
  38. }
  39. WRes LoopThread_StopAndWait(CLoopThread *p)
  40. {
  41. p->stop = 1;
  42. if (Event_Set(&p->startEvent) != 0)
  43. return SZ_ERROR_THREAD;
  44. return Thread_Wait(&p->thread);
  45. }
  46. WRes LoopThread_StartSubThread(CLoopThread *p) { return Event_Set(&p->startEvent); }
  47. WRes LoopThread_WaitSubThread(CLoopThread *p) { return Event_Wait(&p->finishedEvent); }
  48. static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize)
  49. {
  50. return (p && p->Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK;
  51. }
  52. static void MtProgress_Init(CMtProgress *p, ICompressProgress *progress)
  53. {
  54. unsigned i;
  55. for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++)
  56. p->inSizes[i] = p->outSizes[i] = 0;
  57. p->totalInSize = p->totalOutSize = 0;
  58. p->progress = progress;
  59. p->res = SZ_OK;
  60. }
  61. static void MtProgress_Reinit(CMtProgress *p, unsigned index)
  62. {
  63. p->inSizes[index] = 0;
  64. p->outSizes[index] = 0;
  65. }
  66. #define UPDATE_PROGRESS(size, prev, total) \
  67. if (size != (UInt64)(Int64)-1) { total += size - prev; prev = size; }
  68. SRes MtProgress_Set(CMtProgress *p, unsigned index, UInt64 inSize, UInt64 outSize)
  69. {
  70. SRes res;
  71. CriticalSection_Enter(&p->cs);
  72. UPDATE_PROGRESS(inSize, p->inSizes[index], p->totalInSize)
  73. UPDATE_PROGRESS(outSize, p->outSizes[index], p->totalOutSize)
  74. if (p->res == SZ_OK)
  75. p->res = Progress(p->progress, p->totalInSize, p->totalOutSize);
  76. res = p->res;
  77. CriticalSection_Leave(&p->cs);
  78. return res;
  79. }
  80. static void MtProgress_SetError(CMtProgress *p, SRes res)
  81. {
  82. CriticalSection_Enter(&p->cs);
  83. if (p->res == SZ_OK)
  84. p->res = res;
  85. CriticalSection_Leave(&p->cs);
  86. }
  87. static void MtCoder_SetError(CMtCoder* p, SRes res)
  88. {
  89. CriticalSection_Enter(&p->cs);
  90. if (p->res == SZ_OK)
  91. p->res = res;
  92. CriticalSection_Leave(&p->cs);
  93. }
  94. /* ---------- MtThread ---------- */
  95. void CMtThread_Construct(CMtThread *p, CMtCoder *mtCoder)
  96. {
  97. p->mtCoder = mtCoder;
  98. p->outBuf = 0;
  99. p->inBuf = 0;
  100. Event_Construct(&p->canRead);
  101. Event_Construct(&p->canWrite);
  102. LoopThread_Construct(&p->thread);
  103. }
  104. #define RINOK_THREAD(x) { if((x) != 0) return SZ_ERROR_THREAD; }
  105. static void CMtThread_CloseEvents(CMtThread *p)
  106. {
  107. Event_Close(&p->canRead);
  108. Event_Close(&p->canWrite);
  109. }
  110. static void CMtThread_Destruct(CMtThread *p)
  111. {
  112. CMtThread_CloseEvents(p);
  113. if (Thread_WasCreated(&p->thread.thread))
  114. {
  115. LoopThread_StopAndWait(&p->thread);
  116. LoopThread_Close(&p->thread);
  117. }
  118. if (p->mtCoder->alloc)
  119. IAlloc_Free(p->mtCoder->alloc, p->outBuf);
  120. p->outBuf = 0;
  121. if (p->mtCoder->alloc)
  122. IAlloc_Free(p->mtCoder->alloc, p->inBuf);
  123. p->inBuf = 0;
  124. }
  125. #define MY_BUF_ALLOC(buf, size, newSize) \
  126. if (buf == 0 || size != newSize) \
  127. { IAlloc_Free(p->mtCoder->alloc, buf); \
  128. size = newSize; buf = (Byte *)IAlloc_Alloc(p->mtCoder->alloc, size); \
  129. if (buf == 0) return SZ_ERROR_MEM; }
  130. static SRes CMtThread_Prepare(CMtThread *p)
  131. {
  132. MY_BUF_ALLOC(p->inBuf, p->inBufSize, p->mtCoder->blockSize)
  133. MY_BUF_ALLOC(p->outBuf, p->outBufSize, p->mtCoder->destBlockSize)
  134. p->stopReading = False;
  135. p->stopWriting = False;
  136. RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canRead));
  137. RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canWrite));
  138. return SZ_OK;
  139. }
  140. static SRes FullRead(ISeqInStream *stream, Byte *data, size_t *processedSize)
  141. {
  142. size_t size = *processedSize;
  143. *processedSize = 0;
  144. while (size != 0)
  145. {
  146. size_t curSize = size;
  147. SRes res = stream->Read(stream, data, &curSize);
  148. *processedSize += curSize;
  149. data += curSize;
  150. size -= curSize;
  151. RINOK(res);
  152. if (curSize == 0)
  153. return SZ_OK;
  154. }
  155. return SZ_OK;
  156. }
  157. #define GET_NEXT_THREAD(p) &p->mtCoder->threads[p->index == p->mtCoder->numThreads - 1 ? 0 : p->index + 1]
  158. static SRes MtThread_Process(CMtThread *p, Bool *stop)
  159. {
  160. CMtThread *next;
  161. *stop = True;
  162. if (Event_Wait(&p->canRead) != 0)
  163. return SZ_ERROR_THREAD;
  164. next = GET_NEXT_THREAD(p);
  165. if (p->stopReading)
  166. {
  167. next->stopReading = True;
  168. return Event_Set(&next->canRead) == 0 ? SZ_OK : SZ_ERROR_THREAD;
  169. }
  170. {
  171. size_t size = p->mtCoder->blockSize;
  172. size_t destSize = p->outBufSize;
  173. RINOK(FullRead(p->mtCoder->inStream, p->inBuf, &size));
  174. next->stopReading = *stop = (size != p->mtCoder->blockSize);
  175. if (Event_Set(&next->canRead) != 0)
  176. return SZ_ERROR_THREAD;
  177. RINOK(p->mtCoder->mtCallback->Code(p->mtCoder->mtCallback, p->index,
  178. p->outBuf, &destSize, p->inBuf, size, *stop));
  179. MtProgress_Reinit(&p->mtCoder->mtProgress, p->index);
  180. if (Event_Wait(&p->canWrite) != 0)
  181. return SZ_ERROR_THREAD;
  182. if (p->stopWriting)
  183. return SZ_ERROR_FAIL;
  184. if (p->mtCoder->outStream->Write(p->mtCoder->outStream, p->outBuf, destSize) != destSize)
  185. return SZ_ERROR_WRITE;
  186. return Event_Set(&next->canWrite) == 0 ? SZ_OK : SZ_ERROR_THREAD;
  187. }
  188. }
  189. static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp)
  190. {
  191. CMtThread *p = (CMtThread *)pp;
  192. for (;;)
  193. {
  194. Bool stop;
  195. CMtThread *next = GET_NEXT_THREAD(p);
  196. SRes res = MtThread_Process(p, &stop);
  197. if (res != SZ_OK)
  198. {
  199. MtCoder_SetError(p->mtCoder, res);
  200. MtProgress_SetError(&p->mtCoder->mtProgress, res);
  201. next->stopReading = True;
  202. next->stopWriting = True;
  203. Event_Set(&next->canRead);
  204. Event_Set(&next->canWrite);
  205. return res;
  206. }
  207. if (stop)
  208. return 0;
  209. }
  210. }
  211. void MtCoder_Construct(CMtCoder* p)
  212. {
  213. unsigned i;
  214. p->alloc = 0;
  215. for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++)
  216. {
  217. CMtThread *t = &p->threads[i];
  218. t->index = i;
  219. CMtThread_Construct(t, p);
  220. }
  221. CriticalSection_Init(&p->cs);
  222. CriticalSection_Init(&p->mtProgress.cs);
  223. }
  224. void MtCoder_Destruct(CMtCoder* p)
  225. {
  226. unsigned i;
  227. for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++)
  228. CMtThread_Destruct(&p->threads[i]);
  229. CriticalSection_Delete(&p->cs);
  230. CriticalSection_Delete(&p->mtProgress.cs);
  231. }
  232. SRes MtCoder_Code(CMtCoder *p)
  233. {
  234. unsigned i, numThreads = p->numThreads;
  235. SRes res = SZ_OK;
  236. p->res = SZ_OK;
  237. MtProgress_Init(&p->mtProgress, p->progress);
  238. for (i = 0; i < numThreads; i++)
  239. {
  240. RINOK(CMtThread_Prepare(&p->threads[i]));
  241. }
  242. for (i = 0; i < numThreads; i++)
  243. {
  244. CMtThread *t = &p->threads[i];
  245. CLoopThread *lt = &t->thread;
  246. if (!Thread_WasCreated(&lt->thread))
  247. {
  248. lt->func = ThreadFunc;
  249. lt->param = t;
  250. if (LoopThread_Create(lt) != SZ_OK)
  251. {
  252. res = SZ_ERROR_THREAD;
  253. break;
  254. }
  255. }
  256. }
  257. if (res == SZ_OK)
  258. {
  259. unsigned j;
  260. for (i = 0; i < numThreads; i++)
  261. {
  262. CMtThread *t = &p->threads[i];
  263. if (LoopThread_StartSubThread(&t->thread) != SZ_OK)
  264. {
  265. res = SZ_ERROR_THREAD;
  266. p->threads[0].stopReading = True;
  267. break;
  268. }
  269. }
  270. Event_Set(&p->threads[0].canWrite);
  271. Event_Set(&p->threads[0].canRead);
  272. for (j = 0; j < i; j++)
  273. LoopThread_WaitSubThread(&p->threads[j].thread);
  274. }
  275. for (i = 0; i < numThreads; i++)
  276. CMtThread_CloseEvents(&p->threads[i]);
  277. return (res == SZ_OK) ? p->res : res;
  278. }