Annotation of truecrypt/common/encryptionthreadpool.c, revision 1.1

1.1     ! root        1: /*
        !             2:  Copyright (c) 2008 TrueCrypt Foundation. All rights reserved.
        !             3: 
        !             4:  Governed by the TrueCrypt License 2.5 the full text of which is contained
        !             5:  in the file License.txt included in TrueCrypt binary and source code
        !             6:  distribution packages.
        !             7: */
        !             8: 
        !             9: #include "EncryptionThreadPool.h"
        !            10: #include "Pkcs5.h"
        !            11: #ifdef DEVICE_DRIVER
        !            12: #include "Driver/Ntdriver.h"
        !            13: #endif
        !            14: 
        !            15: #define TC_ENC_THREAD_POOL_MAX_THREAD_COUNT 32
        !            16: #define TC_ENC_THREAD_POOL_QUEUE_SIZE (TC_ENC_THREAD_POOL_MAX_THREAD_COUNT * 2)
        !            17: 
        !            18: #ifdef DEVICE_DRIVER
        !            19: 
        !            20: #define TC_THREAD_HANDLE PKTHREAD
        !            21: #define TC_THREAD_PROC VOID
        !            22: 
        !            23: #define TC_SET_EVENT(EVENT) KeSetEvent (&EVENT, IO_DISK_INCREMENT, FALSE)
        !            24: #define TC_CLEAR_EVENT(EVENT) KeClearEvent (&EVENT)
        !            25: 
        !            26: #define TC_MUTEX FAST_MUTEX
        !            27: #define TC_INIT_MUTEX(MUTEX) ExInitializeFastMutex (MUTEX)
        !            28: #define TC_ACQUIRE_MUTEX(MUTEX) ExAcquireFastMutex (MUTEX)
        !            29: #define TC_RELEASE_MUTEX(MUTEX) ExReleaseFastMutex (MUTEX)
        !            30: 
        !            31: #else // !DEVICE_DRIVER
        !            32: 
        !            33: #define TC_THREAD_HANDLE HANDLE
        !            34: #define TC_THREAD_PROC unsigned __stdcall
        !            35: 
        !            36: #define TC_SET_EVENT(EVENT) SetEvent (EVENT)
        !            37: #define TC_CLEAR_EVENT(EVENT) ResetEvent (EVENT)
        !            38: 
        !            39: #define TC_MUTEX CRITICAL_SECTION
        !            40: #define TC_INIT_MUTEX(MUTEX) InitializeCriticalSectionAndSpinCount (MUTEX, 4000)
        !            41: #define TC_ACQUIRE_MUTEX(MUTEX) EnterCriticalSection (MUTEX)
        !            42: #define TC_RELEASE_MUTEX(MUTEX) LeaveCriticalSection (MUTEX)
        !            43: 
        !            44: #endif // !DEVICE_DRIVER
        !            45: 
        !            46: 
        !            47: typedef enum
        !            48: {
        !            49:        WorkItemFree,
        !            50:        WorkItemReady,
        !            51:        WorkItemBusy
        !            52: } WorkItemState;
        !            53: 
        !            54: 
        !            55: typedef struct EncryptionThreadPoolWorkItemStruct
        !            56: {
        !            57:        WorkItemState State;
        !            58:        EncryptionThreadPoolWorkType Type;
        !            59: 
        !            60:        TC_EVENT ItemCompletedEvent;
        !            61: 
        !            62:        struct EncryptionThreadPoolWorkItemStruct *FirstFragment;
        !            63:        LONG OutstandingFragmentCount;
        !            64: 
        !            65:        union
        !            66:        {
        !            67:                struct
        !            68:                {
        !            69:                        PCRYPTO_INFO CryptoInfo;
        !            70:                        byte *Data;
        !            71:                        UINT64_STRUCT StartUnitNo;
        !            72:                        TC_LARGEST_COMPILER_UINT UnitCount;
        !            73: 
        !            74:                } Encryption;
        !            75: 
        !            76:                struct
        !            77:                {
        !            78:                        TC_EVENT *CompletionEvent;
        !            79:                        LONG *CompletionFlag;
        !            80:                        char *DerivedKey;
        !            81:                        int IterationCount;
        !            82:                        TC_EVENT *NoOutstandingWorkItemEvent;
        !            83:                        LONG *OutstandingWorkItemCount;
        !            84:                        char *Password;
        !            85:                        int PasswordLength;
        !            86:                        int Pkcs5Prf;
        !            87:                        char *Salt;
        !            88: 
        !            89:                } KeyDerivation;
        !            90:        };
        !            91: 
        !            92: } EncryptionThreadPoolWorkItem;
        !            93: 
        !            94: 
        !            95: static volatile BOOL ThreadPoolRunning = FALSE;
        !            96: static volatile BOOL StopPending = FALSE;
        !            97: 
        !            98: static size_t ThreadCount;
        !            99: static TC_THREAD_HANDLE ThreadHandles[TC_ENC_THREAD_POOL_MAX_THREAD_COUNT];
        !           100: 
        !           101: static EncryptionThreadPoolWorkItem WorkItemQueue[TC_ENC_THREAD_POOL_QUEUE_SIZE];
        !           102: 
        !           103: static volatile int EnqueuePosition;
        !           104: static volatile int DequeuePosition;
        !           105: 
        !           106: static TC_MUTEX EnqueueMutex;
        !           107: static TC_MUTEX DequeueMutex;
        !           108: 
        !           109: static TC_EVENT WorkItemReadyEvent;
        !           110: static TC_EVENT WorkItemCompletedEvent;
        !           111: 
        !           112: 
        !           113: static WorkItemState GetWorkItemState (EncryptionThreadPoolWorkItem *workItem)
        !           114: {
        !           115:        return InterlockedExchangeAdd ((LONG *) &workItem->State, 0);
        !           116: }
        !           117: 
        !           118: 
        !           119: static void SetWorkItemState (EncryptionThreadPoolWorkItem *workItem, WorkItemState newState)
        !           120: {
        !           121:        InterlockedExchange ((LONG *) &workItem->State, (LONG) newState);
        !           122: }
        !           123: 
        !           124: 
        !           125: static TC_THREAD_PROC EncryptionThreadProc (void *threadArg)
        !           126: {
        !           127:        EncryptionThreadPoolWorkItem *workItem;
        !           128: 
        !           129:        while (!StopPending)
        !           130:        {
        !           131:                TC_ACQUIRE_MUTEX (&DequeueMutex);
        !           132: 
        !           133:                workItem = &WorkItemQueue[DequeuePosition++];
        !           134: 
        !           135:                if (DequeuePosition >= TC_ENC_THREAD_POOL_QUEUE_SIZE)
        !           136:                        DequeuePosition = 0;
        !           137: 
        !           138:                while (!StopPending && GetWorkItemState (workItem) != WorkItemReady)
        !           139:                {
        !           140:                        TC_WAIT_EVENT (WorkItemReadyEvent);
        !           141:                }
        !           142: 
        !           143:                SetWorkItemState (workItem, WorkItemBusy);
        !           144: 
        !           145:                TC_RELEASE_MUTEX (&DequeueMutex);
        !           146: 
        !           147:                if (StopPending)
        !           148:                        break;
        !           149: 
        !           150:                switch (workItem->Type)
        !           151:                {
        !           152:                case DecryptDataUnitsWork:
        !           153:                        DecryptDataUnitsCurrentThread (workItem->Encryption.Data, &workItem->Encryption.StartUnitNo, workItem->Encryption.UnitCount, workItem->Encryption.CryptoInfo);
        !           154:                        break;
        !           155: 
        !           156:                case EncryptDataUnitsWork:
        !           157:                        EncryptDataUnitsCurrentThread (workItem->Encryption.Data, &workItem->Encryption.StartUnitNo, workItem->Encryption.UnitCount, workItem->Encryption.CryptoInfo);
        !           158:                        break;
        !           159: 
        !           160:                case DeriveKeyWork:
        !           161:                        switch (workItem->KeyDerivation.Pkcs5Prf)
        !           162:                        {
        !           163:                        case RIPEMD160:
        !           164:                                derive_key_ripemd160 (workItem->KeyDerivation.Password, workItem->KeyDerivation.PasswordLength, workItem->KeyDerivation.Salt, PKCS5_SALT_SIZE,
        !           165:                                        workItem->KeyDerivation.IterationCount, workItem->KeyDerivation.DerivedKey, GetMaxPkcs5OutSize());
        !           166:                                break;
        !           167: 
        !           168:                        case SHA512:
        !           169:                                derive_key_sha512 (workItem->KeyDerivation.Password, workItem->KeyDerivation.PasswordLength, workItem->KeyDerivation.Salt, PKCS5_SALT_SIZE,
        !           170:                                        workItem->KeyDerivation.IterationCount, workItem->KeyDerivation.DerivedKey, GetMaxPkcs5OutSize());
        !           171:                                break;
        !           172: 
        !           173:                        case WHIRLPOOL:
        !           174:                                derive_key_whirlpool (workItem->KeyDerivation.Password, workItem->KeyDerivation.PasswordLength, workItem->KeyDerivation.Salt, PKCS5_SALT_SIZE,
        !           175:                                        workItem->KeyDerivation.IterationCount, workItem->KeyDerivation.DerivedKey, GetMaxPkcs5OutSize());
        !           176:                                break;
        !           177: 
        !           178:                        case SHA1:
        !           179:                                derive_key_sha1 (workItem->KeyDerivation.Password, workItem->KeyDerivation.PasswordLength, workItem->KeyDerivation.Salt, PKCS5_SALT_SIZE,
        !           180:                                        workItem->KeyDerivation.IterationCount, workItem->KeyDerivation.DerivedKey, GetMaxPkcs5OutSize());
        !           181:                                break;
        !           182: 
        !           183:                        default:                
        !           184:                                TC_THROW_FATAL_EXCEPTION;
        !           185:                        } 
        !           186: 
        !           187:                        InterlockedExchange (workItem->KeyDerivation.CompletionFlag, TRUE);
        !           188:                        TC_SET_EVENT (*workItem->KeyDerivation.CompletionEvent);
        !           189:                        
        !           190:                        if (InterlockedDecrement (workItem->KeyDerivation.OutstandingWorkItemCount) == 0)
        !           191:                                TC_SET_EVENT (*workItem->KeyDerivation.NoOutstandingWorkItemEvent);
        !           192: 
        !           193:                        SetWorkItemState (workItem, WorkItemFree);
        !           194:                        TC_SET_EVENT (WorkItemCompletedEvent);
        !           195:                        continue;
        !           196: 
        !           197:                default:
        !           198:                        TC_THROW_FATAL_EXCEPTION;
        !           199:                }
        !           200: 
        !           201:                if (workItem != workItem->FirstFragment)
        !           202:                {
        !           203:                        SetWorkItemState (workItem, WorkItemFree);
        !           204:                        TC_SET_EVENT (WorkItemCompletedEvent);
        !           205:                }
        !           206: 
        !           207:                if (InterlockedDecrement (&workItem->FirstFragment->OutstandingFragmentCount) == 0)
        !           208:                        TC_SET_EVENT (workItem->FirstFragment->ItemCompletedEvent);
        !           209:        }
        !           210: 
        !           211: #ifdef DEVICE_DRIVER
        !           212:        PsTerminateSystemThread (STATUS_SUCCESS);
        !           213: #else
        !           214:        _endthreadex (0);
        !           215:     return 0;
        !           216: #endif
        !           217: }
        !           218: 
        !           219: 
        !           220: BOOL EncryptionThreadPoolStart ()
        !           221: {
        !           222:        size_t cpuCount, i;
        !           223: 
        !           224:        if (ThreadPoolRunning)
        !           225:                return TRUE;
        !           226: 
        !           227: #ifdef DEVICE_DRIVER
        !           228:        cpuCount = GetCpuCount();
        !           229: #else
        !           230:        {
        !           231:                SYSTEM_INFO sysInfo;
        !           232:                GetSystemInfo (&sysInfo);
        !           233:                cpuCount = sysInfo.dwNumberOfProcessors;
        !           234:        }
        !           235: #endif
        !           236: 
        !           237:        if (cpuCount < 2)
        !           238:                return TRUE;
        !           239: 
        !           240:        if (cpuCount > TC_ENC_THREAD_POOL_MAX_THREAD_COUNT)
        !           241:                cpuCount = TC_ENC_THREAD_POOL_MAX_THREAD_COUNT;
        !           242: 
        !           243:        StopPending = FALSE;
        !           244:        DequeuePosition = 0;
        !           245:        EnqueuePosition = 0;
        !           246: 
        !           247: #ifdef DEVICE_DRIVER
        !           248:        KeInitializeEvent (&WorkItemReadyEvent, SynchronizationEvent, FALSE);
        !           249:        KeInitializeEvent (&WorkItemCompletedEvent, SynchronizationEvent, FALSE);
        !           250: #else
        !           251:        WorkItemReadyEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
        !           252:        if (!WorkItemReadyEvent)
        !           253:                return FALSE;
        !           254:        
        !           255:        WorkItemCompletedEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
        !           256:        if (!WorkItemCompletedEvent)
        !           257:        {
        !           258:                CloseHandle (WorkItemReadyEvent);
        !           259:                return FALSE;
        !           260:        }
        !           261: #endif
        !           262:        
        !           263:        TC_INIT_MUTEX (&DequeueMutex);
        !           264:        TC_INIT_MUTEX (&EnqueueMutex);
        !           265: 
        !           266:        memset (WorkItemQueue, 0, sizeof (WorkItemQueue));
        !           267: 
        !           268:        for (i = 0; i < sizeof (WorkItemQueue) / sizeof (WorkItemQueue[0]); ++i)
        !           269:        {
        !           270:                WorkItemQueue[i].State = WorkItemFree;
        !           271: 
        !           272: #ifdef DEVICE_DRIVER
        !           273:                KeInitializeEvent (&WorkItemQueue[i].ItemCompletedEvent, SynchronizationEvent, FALSE);
        !           274: #else
        !           275:                WorkItemQueue[i].ItemCompletedEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
        !           276:                if (!WorkItemQueue[i].ItemCompletedEvent)
        !           277:                {
        !           278:                        EncryptionThreadPoolStop();
        !           279:                        return FALSE;
        !           280:                }
        !           281: #endif
        !           282:        }
        !           283: 
        !           284:        for (ThreadCount = 0; ThreadCount < cpuCount; ++ThreadCount)
        !           285:        {
        !           286: #ifdef DEVICE_DRIVER
        !           287:                if (!NT_SUCCESS (TCStartThread (EncryptionThreadProc, NULL, &ThreadHandles[ThreadCount])))
        !           288: #else
        !           289:                if (!(ThreadHandles[ThreadCount] = (HANDLE) _beginthreadex (NULL, 0, EncryptionThreadProc, NULL, 0, NULL)))
        !           290: #endif
        !           291:                {
        !           292:                        EncryptionThreadPoolStop();
        !           293:                        return FALSE;
        !           294:                }
        !           295:        }
        !           296: 
        !           297:        ThreadPoolRunning = TRUE;
        !           298:        return TRUE;
        !           299: }
        !           300: 
        !           301: 
        !           302: void EncryptionThreadPoolStop ()
        !           303: {
        !           304:        size_t i;
        !           305: 
        !           306:        if (!ThreadPoolRunning)
        !           307:                return;
        !           308: 
        !           309:        StopPending = TRUE;
        !           310:        TC_SET_EVENT (WorkItemReadyEvent);
        !           311: 
        !           312:        for (i = 0; i < ThreadCount; ++i)
        !           313:        {
        !           314: #ifdef DEVICE_DRIVER
        !           315:                TCStopThread (ThreadHandles[i], &WorkItemReadyEvent);
        !           316: #else
        !           317:                TC_WAIT_EVENT (ThreadHandles[i]);
        !           318: #endif
        !           319:        }
        !           320: 
        !           321:        ThreadCount = 0;
        !           322: 
        !           323: #ifndef DEVICE_DRIVER
        !           324:        DeleteCriticalSection (&DequeueMutex);
        !           325:        DeleteCriticalSection (&EnqueueMutex);
        !           326: 
        !           327:        CloseHandle (WorkItemReadyEvent);
        !           328:        CloseHandle (WorkItemCompletedEvent);
        !           329: 
        !           330:        for (i = 0; i < sizeof (WorkItemQueue) / sizeof (WorkItemQueue[0]); ++i)
        !           331:        {
        !           332:                if (WorkItemQueue[i].ItemCompletedEvent)
        !           333:                        CloseHandle (WorkItemQueue[i].ItemCompletedEvent);
        !           334:        }
        !           335: #endif
        !           336: 
        !           337:        ThreadPoolRunning = FALSE;
        !           338: }
        !           339: 
        !           340: 
        !           341: void EncryptionThreadPoolBeginKeyDerivation (TC_EVENT *completionEvent, TC_EVENT *noOutstandingWorkItemEvent, LONG *completionFlag, LONG *outstandingWorkItemCount, int pkcs5Prf, char *password, int passwordLength, char *salt, int iterationCount, char *derivedKey)
        !           342: {
        !           343:        EncryptionThreadPoolWorkItem *workItem;
        !           344: 
        !           345:        if (!ThreadPoolRunning)
        !           346:                TC_THROW_FATAL_EXCEPTION;
        !           347: 
        !           348:        TC_ACQUIRE_MUTEX (&EnqueueMutex);
        !           349: 
        !           350:        workItem = &WorkItemQueue[EnqueuePosition++];
        !           351:        if (EnqueuePosition >= TC_ENC_THREAD_POOL_QUEUE_SIZE)
        !           352:                EnqueuePosition = 0;
        !           353: 
        !           354:        while (GetWorkItemState (workItem) != WorkItemFree)
        !           355:        {
        !           356:                TC_WAIT_EVENT (WorkItemCompletedEvent);
        !           357:        }
        !           358: 
        !           359:        workItem->Type = DeriveKeyWork;
        !           360:        workItem->KeyDerivation.CompletionEvent = completionEvent;
        !           361:        workItem->KeyDerivation.CompletionFlag = completionFlag;
        !           362:        workItem->KeyDerivation.DerivedKey = derivedKey;
        !           363:        workItem->KeyDerivation.IterationCount = iterationCount;
        !           364:        workItem->KeyDerivation.NoOutstandingWorkItemEvent = noOutstandingWorkItemEvent;
        !           365:        workItem->KeyDerivation.OutstandingWorkItemCount = outstandingWorkItemCount;
        !           366:        workItem->KeyDerivation.Password = password;
        !           367:        workItem->KeyDerivation.PasswordLength = passwordLength;
        !           368:        workItem->KeyDerivation.Pkcs5Prf = pkcs5Prf;
        !           369:        workItem->KeyDerivation.Salt = salt;
        !           370: 
        !           371:        InterlockedIncrement (outstandingWorkItemCount);
        !           372:        TC_CLEAR_EVENT (*noOutstandingWorkItemEvent);
        !           373: 
        !           374:        SetWorkItemState (workItem, WorkItemReady);
        !           375:        TC_SET_EVENT (WorkItemReadyEvent);
        !           376:        TC_RELEASE_MUTEX (&EnqueueMutex);
        !           377: }
        !           378: 
        !           379: 
        !           380: void EncryptionThreadPoolDoWork (EncryptionThreadPoolWorkType type, byte *data, const UINT64_STRUCT *startUnitNo, TC_LARGEST_COMPILER_UINT unitCount, PCRYPTO_INFO cryptoInfo)
        !           381: {
        !           382:        size_t fragmentCount;
        !           383:        size_t unitsPerFragment;
        !           384:        size_t remainder;
        !           385: 
        !           386:        byte *fragmentData;
        !           387:        TC_LARGEST_COMPILER_UINT fragmentStartUnitNo;
        !           388: 
        !           389:        EncryptionThreadPoolWorkItem *workItem;
        !           390:        EncryptionThreadPoolWorkItem *firstFragmentWorkItem;
        !           391:        
        !           392:        if (unitCount == 0)
        !           393:                return;
        !           394:        
        !           395:        if (!ThreadPoolRunning || unitCount == 1)
        !           396:        {
        !           397:                switch (type)
        !           398:                {
        !           399:                case DecryptDataUnitsWork:
        !           400:                        DecryptDataUnitsCurrentThread (data, startUnitNo, unitCount, cryptoInfo);
        !           401:                        break;
        !           402: 
        !           403:                case EncryptDataUnitsWork:
        !           404:                        EncryptDataUnitsCurrentThread (data, startUnitNo, unitCount, cryptoInfo);
        !           405:                        break;
        !           406: 
        !           407:                default:
        !           408:                        TC_THROW_FATAL_EXCEPTION;
        !           409:                }
        !           410: 
        !           411:                return;
        !           412:        }
        !           413: 
        !           414:        if (unitCount <= ThreadCount)
        !           415:        {
        !           416:                fragmentCount = (size_t) unitCount;
        !           417:                unitsPerFragment = 1;
        !           418:                remainder = 0;
        !           419:        }
        !           420:        else
        !           421:        {
        !           422:                /* Note that it is not efficient to divide the data into fragments smaller than a few hundred bytes.
        !           423:                The reason is that the overhead associated with thread handling would in most cases make a multi-threaded 
        !           424:                process actually slower than a single-threaded process. */
        !           425: 
        !           426:                fragmentCount = ThreadCount;
        !           427:                unitsPerFragment = (size_t) unitCount / ThreadCount;
        !           428:                remainder = (size_t) unitCount % ThreadCount;
        !           429: 
        !           430:                if (remainder > 0)
        !           431:                        ++unitsPerFragment;
        !           432:        }
        !           433:        
        !           434:        fragmentData = data;
        !           435:        fragmentStartUnitNo = startUnitNo->Value;
        !           436: 
        !           437:        TC_ACQUIRE_MUTEX (&EnqueueMutex);
        !           438:        firstFragmentWorkItem = &WorkItemQueue[EnqueuePosition];
        !           439: 
        !           440:        while (GetWorkItemState (firstFragmentWorkItem) != WorkItemFree)
        !           441:        {
        !           442:                TC_WAIT_EVENT (WorkItemCompletedEvent);
        !           443:        }
        !           444: 
        !           445:        firstFragmentWorkItem->OutstandingFragmentCount = fragmentCount;
        !           446: 
        !           447:        while (fragmentCount-- > 0)
        !           448:        {
        !           449:                workItem = &WorkItemQueue[EnqueuePosition++];
        !           450:                if (EnqueuePosition >= TC_ENC_THREAD_POOL_QUEUE_SIZE)
        !           451:                        EnqueuePosition = 0;
        !           452: 
        !           453:                while (GetWorkItemState (workItem) != WorkItemFree)
        !           454:                {
        !           455:                        TC_WAIT_EVENT (WorkItemCompletedEvent);
        !           456:                }
        !           457: 
        !           458:                workItem->Type = type;
        !           459:                workItem->FirstFragment = firstFragmentWorkItem;
        !           460: 
        !           461:                workItem->Encryption.CryptoInfo = cryptoInfo;
        !           462:                workItem->Encryption.Data = fragmentData;
        !           463:                workItem->Encryption.UnitCount = unitsPerFragment;
        !           464:                workItem->Encryption.StartUnitNo.Value = fragmentStartUnitNo;
        !           465: 
        !           466:                fragmentData += unitsPerFragment * ENCRYPTION_DATA_UNIT_SIZE;
        !           467:                fragmentStartUnitNo += unitsPerFragment;
        !           468: 
        !           469:                if (remainder > 0 && --remainder == 0)
        !           470:                        --unitsPerFragment;
        !           471: 
        !           472:                SetWorkItemState (workItem, WorkItemReady);
        !           473:                TC_SET_EVENT (WorkItemReadyEvent);
        !           474:        }
        !           475: 
        !           476:        TC_RELEASE_MUTEX (&EnqueueMutex);
        !           477: 
        !           478:        TC_WAIT_EVENT (firstFragmentWorkItem->ItemCompletedEvent);
        !           479:        SetWorkItemState (firstFragmentWorkItem, WorkItemFree);
        !           480:        TC_SET_EVENT (WorkItemCompletedEvent);
        !           481: }
        !           482: 
        !           483: 
        !           484: size_t GetEncryptionThreadCount ()
        !           485: {
        !           486:        return ThreadPoolRunning ? ThreadCount : 0;
        !           487: }
        !           488: 
        !           489: 
        !           490: BOOL IsEncryptionThreadPoolRunning ()
        !           491: {
        !           492:        return ThreadPoolRunning;
        !           493: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.