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

1.1       root        1: /*
                      2:  Copyright (c) 2008 TrueCrypt Foundation. All rights reserved.
                      3: 
1.1.1.3 ! root        4:  Governed by the TrueCrypt License 2.7 the full text of which is contained
1.1       root        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.