other-licenses/7zstub/src/7zip/Archive/Common/CoderMixer2MT.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 // CoderMixer2MT.cpp
michael@0 2
michael@0 3 #include "StdAfx.h"
michael@0 4
michael@0 5 #include "CoderMixer2MT.h"
michael@0 6 #include "CrossThreadProgress.h"
michael@0 7
michael@0 8 using namespace NWindows;
michael@0 9 using namespace NSynchronization;
michael@0 10
michael@0 11 namespace NCoderMixer2 {
michael@0 12
michael@0 13 CThreadCoderInfo::CThreadCoderInfo(UInt32 numInStreams, UInt32 numOutStreams):
michael@0 14 ExitEvent(NULL),
michael@0 15 CompressEvent(NULL),
michael@0 16 CompressionCompletedEvent(NULL),
michael@0 17 CCoderInfo(numInStreams, numOutStreams)
michael@0 18 {
michael@0 19 InStreams.Reserve(NumInStreams);
michael@0 20 InStreamPointers.Reserve(NumInStreams);
michael@0 21 OutStreams.Reserve(NumOutStreams);
michael@0 22 OutStreamPointers.Reserve(NumOutStreams);
michael@0 23 }
michael@0 24
michael@0 25 void CThreadCoderInfo::CreateEvents()
michael@0 26 {
michael@0 27 CompressEvent = new CAutoResetEvent(false);
michael@0 28 CompressionCompletedEvent = new CAutoResetEvent(false);
michael@0 29 }
michael@0 30
michael@0 31 CThreadCoderInfo::~CThreadCoderInfo()
michael@0 32 {
michael@0 33 if (CompressEvent != NULL)
michael@0 34 delete CompressEvent;
michael@0 35 if (CompressionCompletedEvent != NULL)
michael@0 36 delete CompressionCompletedEvent;
michael@0 37 }
michael@0 38
michael@0 39 class CCoderInfoFlusher2
michael@0 40 {
michael@0 41 CThreadCoderInfo *m_CoderInfo;
michael@0 42 public:
michael@0 43 CCoderInfoFlusher2(CThreadCoderInfo *coderInfo): m_CoderInfo(coderInfo) {}
michael@0 44 ~CCoderInfoFlusher2()
michael@0 45 {
michael@0 46 int i;
michael@0 47 for (i = 0; i < m_CoderInfo->InStreams.Size(); i++)
michael@0 48 m_CoderInfo->InStreams[i].Release();
michael@0 49 for (i = 0; i < m_CoderInfo->OutStreams.Size(); i++)
michael@0 50 m_CoderInfo->OutStreams[i].Release();
michael@0 51 m_CoderInfo->CompressionCompletedEvent->Set();
michael@0 52 }
michael@0 53 };
michael@0 54
michael@0 55 bool CThreadCoderInfo::WaitAndCode()
michael@0 56 {
michael@0 57 HANDLE events[2] = { ExitEvent, *CompressEvent };
michael@0 58 DWORD waitResult = ::WaitForMultipleObjects(2, events, FALSE, INFINITE);
michael@0 59 if (waitResult == WAIT_OBJECT_0 + 0)
michael@0 60 return false;
michael@0 61
michael@0 62 {
michael@0 63 InStreamPointers.Clear();
michael@0 64 OutStreamPointers.Clear();
michael@0 65 UInt32 i;
michael@0 66 for (i = 0; i < NumInStreams; i++)
michael@0 67 {
michael@0 68 if (InSizePointers[i] != NULL)
michael@0 69 InSizePointers[i] = &InSizes[i];
michael@0 70 InStreamPointers.Add(InStreams[i]);
michael@0 71 }
michael@0 72 for (i = 0; i < NumOutStreams; i++)
michael@0 73 {
michael@0 74 if (OutSizePointers[i] != NULL)
michael@0 75 OutSizePointers[i] = &OutSizes[i];
michael@0 76 OutStreamPointers.Add(OutStreams[i]);
michael@0 77 }
michael@0 78 CCoderInfoFlusher2 coderInfoFlusher(this);
michael@0 79 if (Coder)
michael@0 80 Result = Coder->Code(InStreamPointers[0],
michael@0 81 OutStreamPointers[0],
michael@0 82 InSizePointers[0],
michael@0 83 OutSizePointers[0],
michael@0 84 Progress);
michael@0 85 else
michael@0 86 Result = Coder2->Code(&InStreamPointers.Front(),
michael@0 87 &InSizePointers.Front(),
michael@0 88 NumInStreams,
michael@0 89 &OutStreamPointers.Front(),
michael@0 90 &OutSizePointers.Front(),
michael@0 91 NumOutStreams,
michael@0 92 Progress);
michael@0 93 }
michael@0 94 return true;
michael@0 95 }
michael@0 96
michael@0 97 static void SetSizes(const UInt64 **srcSizes, CRecordVector<UInt64> &sizes,
michael@0 98 CRecordVector<const UInt64 *> &sizePointers, UInt32 numItems)
michael@0 99 {
michael@0 100 sizes.Clear();
michael@0 101 sizePointers.Clear();
michael@0 102 for(UInt32 i = 0; i < numItems; i++)
michael@0 103 {
michael@0 104 if (srcSizes == 0 || srcSizes[i] == NULL)
michael@0 105 {
michael@0 106 sizes.Add(0);
michael@0 107 sizePointers.Add(NULL);
michael@0 108 }
michael@0 109 else
michael@0 110 {
michael@0 111 sizes.Add(*srcSizes[i]);
michael@0 112 sizePointers.Add(&sizes.Back());
michael@0 113 }
michael@0 114 }
michael@0 115 }
michael@0 116
michael@0 117
michael@0 118 void CThreadCoderInfo::SetCoderInfo(const UInt64 **inSizes,
michael@0 119 const UInt64 **outSizes, ICompressProgressInfo *progress)
michael@0 120 {
michael@0 121 Progress = progress;
michael@0 122 SetSizes(inSizes, InSizes, InSizePointers, NumInStreams);
michael@0 123 SetSizes(outSizes, OutSizes, OutSizePointers, NumOutStreams);
michael@0 124 }
michael@0 125
michael@0 126 static DWORD WINAPI CoderThread(void *threadCoderInfo)
michael@0 127 {
michael@0 128 while(true)
michael@0 129 {
michael@0 130 if (!((CThreadCoderInfo *)threadCoderInfo)->WaitAndCode())
michael@0 131 return 0;
michael@0 132 }
michael@0 133 }
michael@0 134
michael@0 135 //////////////////////////////////////
michael@0 136 // CCoderMixer2MT
michael@0 137
michael@0 138 static DWORD WINAPI MainCoderThread(void *threadCoderInfo)
michael@0 139 {
michael@0 140 while(true)
michael@0 141 {
michael@0 142 if (!((CCoderMixer2MT *)threadCoderInfo)->MyCode())
michael@0 143 return 0;
michael@0 144 }
michael@0 145 }
michael@0 146
michael@0 147 CCoderMixer2MT::CCoderMixer2MT()
michael@0 148 {
michael@0 149 if (!_mainThread.Create(MainCoderThread, this))
michael@0 150 throw 271825;
michael@0 151 }
michael@0 152
michael@0 153 CCoderMixer2MT::~CCoderMixer2MT()
michael@0 154 {
michael@0 155 _exitEvent.Set();
michael@0 156 _mainThread.Wait();
michael@0 157 for(int i = 0; i < _threads.Size(); i++)
michael@0 158 {
michael@0 159 _threads[i].Wait();
michael@0 160 _threads[i].Close();
michael@0 161 }
michael@0 162 }
michael@0 163
michael@0 164 void CCoderMixer2MT::SetBindInfo(const CBindInfo &bindInfo)
michael@0 165 {
michael@0 166 _bindInfo = bindInfo;
michael@0 167 _streamBinders.Clear();
michael@0 168 for(int i = 0; i < _bindInfo.BindPairs.Size(); i++)
michael@0 169 {
michael@0 170 _streamBinders.Add(CStreamBinder());
michael@0 171 _streamBinders.Back().CreateEvents();
michael@0 172 }
michael@0 173 }
michael@0 174
michael@0 175 void CCoderMixer2MT::AddCoderCommon()
michael@0 176 {
michael@0 177 int index = _coderInfoVector.Size();
michael@0 178 const CCoderStreamsInfo &CoderStreamsInfo = _bindInfo.Coders[index];
michael@0 179
michael@0 180 CThreadCoderInfo threadCoderInfo(CoderStreamsInfo.NumInStreams,
michael@0 181 CoderStreamsInfo.NumOutStreams);
michael@0 182 _coderInfoVector.Add(threadCoderInfo);
michael@0 183 _coderInfoVector.Back().CreateEvents();
michael@0 184 _coderInfoVector.Back().ExitEvent = _exitEvent;
michael@0 185 _compressingCompletedEvents.Add(*_coderInfoVector.Back().CompressionCompletedEvent);
michael@0 186
michael@0 187 NWindows::CThread newThread;
michael@0 188 _threads.Add(newThread);
michael@0 189 if (!_threads.Back().Create(CoderThread, &_coderInfoVector.Back()))
michael@0 190 throw 271824;
michael@0 191 }
michael@0 192
michael@0 193 void CCoderMixer2MT::AddCoder(ICompressCoder *coder)
michael@0 194 {
michael@0 195 AddCoderCommon();
michael@0 196 _coderInfoVector.Back().Coder = coder;
michael@0 197 }
michael@0 198
michael@0 199 void CCoderMixer2MT::AddCoder2(ICompressCoder2 *coder)
michael@0 200 {
michael@0 201 AddCoderCommon();
michael@0 202 _coderInfoVector.Back().Coder2 = coder;
michael@0 203 }
michael@0 204
michael@0 205 /*
michael@0 206 void CCoderMixer2MT::FinishAddingCoders()
michael@0 207 {
michael@0 208 for(int i = 0; i < _coderInfoVector.Size(); i++)
michael@0 209 {
michael@0 210 DWORD id;
michael@0 211 HANDLE newThread = ::CreateThread(NULL, 0, CoderThread,
michael@0 212 &_coderInfoVector[i], 0, &id);
michael@0 213 if (newThread == 0)
michael@0 214 throw 271824;
michael@0 215 _threads.Add(newThread);
michael@0 216 }
michael@0 217 }
michael@0 218 */
michael@0 219
michael@0 220 void CCoderMixer2MT::ReInit()
michael@0 221 {
michael@0 222 for(int i = 0; i < _streamBinders.Size(); i++)
michael@0 223 _streamBinders[i].ReInit();
michael@0 224 }
michael@0 225
michael@0 226
michael@0 227 STDMETHODIMP CCoderMixer2MT::Init(ISequentialInStream **inStreams,
michael@0 228 ISequentialOutStream **outStreams)
michael@0 229 {
michael@0 230 if (_coderInfoVector.Size() != _bindInfo.Coders.Size())
michael@0 231 throw 0;
michael@0 232 int i;
michael@0 233 for(i = 0; i < _coderInfoVector.Size(); i++)
michael@0 234 {
michael@0 235 CThreadCoderInfo &coderInfo = _coderInfoVector[i];
michael@0 236 const CCoderStreamsInfo &coderStreamsInfo = _bindInfo.Coders[i];
michael@0 237 coderInfo.InStreams.Clear();
michael@0 238 UInt32 j;
michael@0 239 for(j = 0; j < coderStreamsInfo.NumInStreams; j++)
michael@0 240 coderInfo.InStreams.Add(NULL);
michael@0 241 coderInfo.OutStreams.Clear();
michael@0 242 for(j = 0; j < coderStreamsInfo.NumOutStreams; j++)
michael@0 243 coderInfo.OutStreams.Add(NULL);
michael@0 244 }
michael@0 245
michael@0 246 for(i = 0; i < _bindInfo.BindPairs.Size(); i++)
michael@0 247 {
michael@0 248 const CBindPair &bindPair = _bindInfo.BindPairs[i];
michael@0 249 UInt32 inCoderIndex, inCoderStreamIndex;
michael@0 250 UInt32 outCoderIndex, outCoderStreamIndex;
michael@0 251 _bindInfo.FindInStream(bindPair.InIndex, inCoderIndex, inCoderStreamIndex);
michael@0 252 _bindInfo.FindOutStream(bindPair.OutIndex, outCoderIndex, outCoderStreamIndex);
michael@0 253
michael@0 254 _streamBinders[i].CreateStreams(
michael@0 255 &_coderInfoVector[inCoderIndex].InStreams[inCoderStreamIndex],
michael@0 256 &_coderInfoVector[outCoderIndex].OutStreams[outCoderStreamIndex]);
michael@0 257 }
michael@0 258
michael@0 259 for(i = 0; i < _bindInfo.InStreams.Size(); i++)
michael@0 260 {
michael@0 261 UInt32 inCoderIndex, inCoderStreamIndex;
michael@0 262 _bindInfo.FindInStream(_bindInfo.InStreams[i], inCoderIndex, inCoderStreamIndex);
michael@0 263 _coderInfoVector[inCoderIndex].InStreams[inCoderStreamIndex] = inStreams[i];
michael@0 264 }
michael@0 265
michael@0 266 for(i = 0; i < _bindInfo.OutStreams.Size(); i++)
michael@0 267 {
michael@0 268 UInt32 outCoderIndex, outCoderStreamIndex;
michael@0 269 _bindInfo.FindOutStream(_bindInfo.OutStreams[i], outCoderIndex, outCoderStreamIndex);
michael@0 270 _coderInfoVector[outCoderIndex].OutStreams[outCoderStreamIndex] = outStreams[i];
michael@0 271 }
michael@0 272 return S_OK;
michael@0 273 }
michael@0 274
michael@0 275
michael@0 276 bool CCoderMixer2MT::MyCode()
michael@0 277 {
michael@0 278 HANDLE events[2] = { _exitEvent, _startCompressingEvent };
michael@0 279 DWORD waitResult = ::WaitForMultipleObjects(2, events, FALSE, INFINITE);
michael@0 280 if (waitResult == WAIT_OBJECT_0 + 0)
michael@0 281 return false;
michael@0 282
michael@0 283 for(int i = 0; i < _coderInfoVector.Size(); i++)
michael@0 284 _coderInfoVector[i].CompressEvent->Set();
michael@0 285 DWORD result = ::WaitForMultipleObjects(_compressingCompletedEvents.Size(),
michael@0 286 &_compressingCompletedEvents.Front(), TRUE, INFINITE);
michael@0 287
michael@0 288 _compressingFinishedEvent.Set();
michael@0 289
michael@0 290 return true;
michael@0 291 }
michael@0 292
michael@0 293
michael@0 294 STDMETHODIMP CCoderMixer2MT::Code(ISequentialInStream **inStreams,
michael@0 295 const UInt64 **inSizes,
michael@0 296 UInt32 numInStreams,
michael@0 297 ISequentialOutStream **outStreams,
michael@0 298 const UInt64 **outSizes,
michael@0 299 UInt32 numOutStreams,
michael@0 300 ICompressProgressInfo *progress)
michael@0 301 {
michael@0 302 if (numInStreams != (UInt32)_bindInfo.InStreams.Size() ||
michael@0 303 numOutStreams != (UInt32)_bindInfo.OutStreams.Size())
michael@0 304 return E_INVALIDARG;
michael@0 305
michael@0 306 Init(inStreams, outStreams);
michael@0 307
michael@0 308 _compressingFinishedEvent.Reset(); // ?
michael@0 309
michael@0 310 CCrossThreadProgress *progressSpec = new CCrossThreadProgress;
michael@0 311 CMyComPtr<ICompressProgressInfo> crossProgress = progressSpec;
michael@0 312 progressSpec->Init();
michael@0 313 _coderInfoVector[_progressCoderIndex].Progress = crossProgress;
michael@0 314
michael@0 315 _startCompressingEvent.Set();
michael@0 316
michael@0 317
michael@0 318 while (true)
michael@0 319 {
michael@0 320 HANDLE events[2] = {_compressingFinishedEvent, progressSpec->ProgressEvent };
michael@0 321 DWORD waitResult = ::WaitForMultipleObjects(2, events, FALSE, INFINITE);
michael@0 322 if (waitResult == WAIT_OBJECT_0 + 0)
michael@0 323 break;
michael@0 324 if (progress != NULL)
michael@0 325 progressSpec->Result = progress->SetRatioInfo(progressSpec->InSize,
michael@0 326 progressSpec->OutSize);
michael@0 327 else
michael@0 328 progressSpec->Result = S_OK;
michael@0 329 progressSpec->WaitEvent.Set();
michael@0 330 }
michael@0 331
michael@0 332 int i;
michael@0 333 for(i = 0; i < _coderInfoVector.Size(); i++)
michael@0 334 {
michael@0 335 HRESULT result = _coderInfoVector[i].Result;
michael@0 336 if (result == S_FALSE)
michael@0 337 return result;
michael@0 338 }
michael@0 339 for(i = 0; i < _coderInfoVector.Size(); i++)
michael@0 340 {
michael@0 341 HRESULT result = _coderInfoVector[i].Result;
michael@0 342 if (result != S_OK && result != E_FAIL)
michael@0 343 return result;
michael@0 344 }
michael@0 345 for(i = 0; i < _coderInfoVector.Size(); i++)
michael@0 346 {
michael@0 347 HRESULT result = _coderInfoVector[i].Result;
michael@0 348 if (result != S_OK)
michael@0 349 return result;
michael@0 350 }
michael@0 351 return S_OK;
michael@0 352 }
michael@0 353
michael@0 354 UInt64 CCoderMixer2MT::GetWriteProcessedSize(UInt32 binderIndex) const
michael@0 355 {
michael@0 356 return _streamBinders[binderIndex].ProcessedSize;
michael@0 357 }
michael@0 358
michael@0 359 }

mercurial