"Fossies" - the Fresh Open Source Software Archive

Member "src/Volume/EncryptionThreadPool.cpp" (10 Oct 2018, 7717 Bytes) of package /windows/misc/VeraCrypt_1.23-Hotfix-2_Source.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "EncryptionThreadPool.cpp" see the Fossies "Dox" file reference documentation.

    1 /*
    2  Derived from source code of TrueCrypt 7.1a, which is
    3  Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
    4  by the TrueCrypt License 3.0.
    5 
    6  Modifications and additions to the original source code (contained in this file)
    7  and all other portions of this file are Copyright (c) 2013-2017 IDRIX
    8  and are governed by the Apache License 2.0 the full text of which is
    9  contained in the file License.txt included in VeraCrypt binary and source
   10  code distribution packages.
   11 */
   12 
   13 #ifdef TC_UNIX
   14 #   include <unistd.h>
   15 #endif
   16 
   17 #ifdef TC_MACOSX
   18 #   include <sys/types.h>
   19 #   include <sys/sysctl.h>
   20 #endif
   21 
   22 #include "Platform/SyncEvent.h"
   23 #include "Platform/SystemLog.h"
   24 #include "Common/Crypto.h"
   25 #include "EncryptionThreadPool.h"
   26 
   27 namespace VeraCrypt
   28 {
   29     void EncryptionThreadPool::DoWork (WorkType::Enum type, const EncryptionMode *encryptionMode, byte *data, uint64 startUnitNo, uint64 unitCount, size_t sectorSize)
   30     {
   31         size_t fragmentCount;
   32         size_t unitsPerFragment;
   33         size_t remainder;
   34 
   35         byte *fragmentData;
   36         uint64 fragmentStartUnitNo;
   37 
   38         WorkItem *workItem;
   39         WorkItem *firstFragmentWorkItem;
   40 
   41         if (unitCount == 0)
   42             return;
   43 
   44         if (!ThreadPoolRunning || unitCount == 1)
   45         {
   46             switch (type)
   47             {
   48             case WorkType::DecryptDataUnits:
   49                 encryptionMode->DecryptSectorsCurrentThread (data, startUnitNo, unitCount, sectorSize);
   50                 break;
   51 
   52             case WorkType::EncryptDataUnits:
   53                 encryptionMode->EncryptSectorsCurrentThread (data, startUnitNo, unitCount, sectorSize);
   54                 break;
   55 
   56             default:
   57                 throw ParameterIncorrect (SRC_POS);
   58             }
   59 
   60             return;
   61         }
   62 
   63         if (unitCount <= ThreadCount)
   64         {
   65             fragmentCount = (size_t) unitCount;
   66             unitsPerFragment = 1;
   67             remainder = 0;
   68         }
   69         else
   70         {
   71             fragmentCount = ThreadCount;
   72             unitsPerFragment = (size_t) unitCount / ThreadCount;
   73             remainder = (size_t) unitCount % ThreadCount;
   74 
   75             if (remainder > 0)
   76                 ++unitsPerFragment;
   77         }
   78 
   79         fragmentData = data;
   80         fragmentStartUnitNo = startUnitNo;
   81 
   82         {
   83             ScopeLock lock (EnqueueMutex);
   84             firstFragmentWorkItem = &WorkItemQueue[EnqueuePosition];
   85 
   86             while (firstFragmentWorkItem->State != WorkItem::State::Free)
   87             {
   88                 WorkItemCompletedEvent.Wait();
   89             }
   90 
   91             firstFragmentWorkItem->OutstandingFragmentCount.Set (fragmentCount);
   92             firstFragmentWorkItem->ItemException.reset();
   93 
   94             while (fragmentCount-- > 0)
   95             {
   96                 workItem = &WorkItemQueue[EnqueuePosition++];
   97 
   98                 if (EnqueuePosition >= QueueSize)
   99                     EnqueuePosition = 0;
  100 
  101                 while (workItem->State != WorkItem::State::Free)
  102                 {
  103                     WorkItemCompletedEvent.Wait();
  104                 }
  105 
  106                 workItem->Type = type;
  107                 workItem->FirstFragment = firstFragmentWorkItem;
  108 
  109                 workItem->Encryption.Mode = encryptionMode;
  110                 workItem->Encryption.Data = fragmentData;
  111                 workItem->Encryption.UnitCount = unitsPerFragment;
  112                 workItem->Encryption.StartUnitNo = fragmentStartUnitNo;
  113                 workItem->Encryption.SectorSize = sectorSize;
  114 
  115                 fragmentData += unitsPerFragment * sectorSize;
  116                 fragmentStartUnitNo += unitsPerFragment;
  117 
  118                 if (remainder > 0 && --remainder == 0)
  119                     --unitsPerFragment;
  120 
  121                 workItem->State.Set (WorkItem::State::Ready);
  122                 WorkItemReadyEvent.Signal();
  123             }
  124         }
  125 
  126         firstFragmentWorkItem->ItemCompletedEvent.Wait();
  127 
  128         auto_ptr <Exception> itemException;
  129         if (firstFragmentWorkItem->ItemException.get())
  130             itemException = firstFragmentWorkItem->ItemException;
  131 
  132         firstFragmentWorkItem->State.Set (WorkItem::State::Free);
  133         WorkItemCompletedEvent.Signal();
  134 
  135         if (itemException.get())
  136             itemException->Throw();
  137     }
  138 
  139     void EncryptionThreadPool::Start ()
  140     {
  141         if (ThreadPoolRunning)
  142             return;
  143 
  144         size_t cpuCount;
  145 
  146 #ifdef TC_WINDOWS
  147 
  148         SYSTEM_INFO sysInfo;
  149         GetSystemInfo (&sysInfo);
  150         cpuCount = sysInfo.dwNumberOfProcessors;
  151 
  152 #elif defined (_SC_NPROCESSORS_ONLN)
  153 
  154         cpuCount = (size_t) sysconf (_SC_NPROCESSORS_ONLN);
  155         if (cpuCount == (size_t) -1)
  156             cpuCount = 1;
  157 
  158 #elif defined (TC_MACOSX)
  159 
  160         int cpuCountSys;
  161         int mib[2] = { CTL_HW, HW_NCPU };
  162 
  163         size_t len = sizeof (cpuCountSys);
  164         if (sysctl (mib, 2, &cpuCountSys, &len, nullptr, 0) == -1)
  165             cpuCountSys = 1;
  166 
  167         cpuCount = (size_t) cpuCountSys;
  168 
  169 #else
  170 #   error Cannot determine CPU count
  171 #endif
  172 
  173         if (cpuCount < 2)
  174             return;
  175 
  176         if (cpuCount > MaxThreadCount)
  177             cpuCount = MaxThreadCount;
  178 
  179         StopPending = false;
  180         DequeuePosition = 0;
  181         EnqueuePosition = 0;
  182 
  183         for (size_t i = 0; i < sizeof (WorkItemQueue) / sizeof (WorkItemQueue[0]); ++i)
  184         {
  185             WorkItemQueue[i].State.Set (WorkItem::State::Free);
  186         }
  187 
  188         try
  189         {
  190             for (ThreadCount = 0; ThreadCount < cpuCount; ++ThreadCount)
  191             {
  192                 struct ThreadFunctor : public Functor
  193                 {
  194                     virtual void operator() ()
  195                     {
  196                         WorkThreadProc();
  197                     }
  198                 };
  199 
  200                 make_shared_auto (Thread, thread);
  201                 thread->Start (new ThreadFunctor ());
  202                 RunningThreads.push_back (thread);
  203             }
  204         }
  205         catch (...)
  206         {
  207             try
  208             {
  209                 ThreadPoolRunning = true;
  210                 Stop();
  211             } catch (...) { }
  212 
  213             throw;
  214         }
  215 
  216         ThreadPoolRunning = true;
  217     }
  218 
  219     void EncryptionThreadPool::Stop ()
  220     {
  221         if (!ThreadPoolRunning)
  222             return;
  223 
  224         StopPending = true;
  225         WorkItemReadyEvent.Signal();
  226 
  227         foreach_ref (const Thread &thread, RunningThreads)
  228         {
  229             thread.Join();
  230         }
  231 
  232         ThreadCount = 0;
  233         ThreadPoolRunning = false;
  234     }
  235 
  236     void EncryptionThreadPool::WorkThreadProc ()
  237     {
  238         try
  239         {
  240             WorkItem *workItem;
  241 
  242             while (!StopPending)
  243             {
  244                 {
  245                     ScopeLock lock (DequeueMutex);
  246 
  247                     workItem = &WorkItemQueue[DequeuePosition++];
  248 
  249                     if (DequeuePosition >= QueueSize)
  250                         DequeuePosition = 0;
  251 
  252                     while (!StopPending && workItem->State != WorkItem::State::Ready)
  253                     {
  254                         WorkItemReadyEvent.Wait();
  255                     }
  256 
  257                     workItem->State.Set (WorkItem::State::Busy);
  258                 }
  259 
  260                 if (StopPending)
  261                     break;
  262 
  263                 try
  264                 {
  265                     switch (workItem->Type)
  266                     {
  267                     case WorkType::DecryptDataUnits:
  268                         workItem->Encryption.Mode->DecryptSectorsCurrentThread (workItem->Encryption.Data, workItem->Encryption.StartUnitNo, workItem->Encryption.UnitCount, workItem->Encryption.SectorSize);
  269                         break;
  270 
  271                     case WorkType::EncryptDataUnits:
  272                         workItem->Encryption.Mode->EncryptSectorsCurrentThread (workItem->Encryption.Data, workItem->Encryption.StartUnitNo, workItem->Encryption.UnitCount, workItem->Encryption.SectorSize);
  273                         break;
  274 
  275                     default:
  276                         throw ParameterIncorrect (SRC_POS);
  277                     }
  278                 }
  279                 catch (Exception &e)
  280                 {
  281                     workItem->FirstFragment->ItemException.reset (e.CloneNew());
  282                 }
  283                 catch (exception &e)
  284                 {
  285                     workItem->FirstFragment->ItemException.reset (new ExternalException (SRC_POS, StringConverter::ToExceptionString (e)));
  286                 }
  287                 catch (...)
  288                 {
  289                     workItem->FirstFragment->ItemException.reset (new UnknownException (SRC_POS));
  290                 }
  291 
  292                 if (workItem != workItem->FirstFragment)
  293                 {
  294                     workItem->State.Set (WorkItem::State::Free);
  295                     WorkItemCompletedEvent.Signal();
  296                 }
  297 
  298                 if (workItem->FirstFragment->OutstandingFragmentCount.Decrement() == 0)
  299                     workItem->FirstFragment->ItemCompletedEvent.Signal();
  300             }
  301         }
  302         catch (exception &e)
  303         {
  304             SystemLog::WriteException (e);
  305         }
  306         catch (...)
  307         {
  308             SystemLog::WriteException (UnknownException (SRC_POS));
  309         }
  310     }
  311 
  312     volatile bool EncryptionThreadPool::ThreadPoolRunning = false;
  313     volatile bool EncryptionThreadPool::StopPending = false;
  314 
  315     size_t EncryptionThreadPool::ThreadCount;
  316 
  317     EncryptionThreadPool::WorkItem EncryptionThreadPool::WorkItemQueue[QueueSize];
  318 
  319     volatile size_t EncryptionThreadPool::EnqueuePosition;
  320     volatile size_t EncryptionThreadPool::DequeuePosition;
  321 
  322     Mutex EncryptionThreadPool::EnqueueMutex;
  323     Mutex EncryptionThreadPool::DequeueMutex;
  324 
  325     SyncEvent EncryptionThreadPool::WorkItemReadyEvent;
  326     SyncEvent EncryptionThreadPool::WorkItemCompletedEvent;
  327 
  328     list < shared_ptr <Thread> > EncryptionThreadPool::RunningThreads;
  329 }