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

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

unix.superglobalmegacorp.com

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