void PoolRelease( MemPool* pPool ) { if ( pPool ) { bool result = KMutexLock( &pPool->mutex, WAIT_FOREVER ); if ( result ) { KMutexDelete( &pPool->mutex ); memset( pPool->pBackingStore, 0, pPool->backingBufferSize ); pPool->pBackingStore = 0; pPool->pFreeBits = 0; } else{ LOG( "%s(): Unable to lock mutex for release", __FUNCTION__ ); assert( 0 ); } } }
void PoolFree( MemPool* pPool, void* buf ) { if ( pPool && buf ) { uint32_t indexToFree = ( uint32_t )( (uint8_t*)buf - (uint8_t*)pPool->pBackingStore ); if ( indexToFree >= pPool->numOfUnits ) { LOG( "%s(): Got out of bounds index to free: %d, ptr: %p (start: %p)", __FUNCTION__, indexToFree, buf, pPool->pBackingStore ); assert( 0 ); } if ( KMutexLock( &pPool->mutex, WAIT_FOREVER ) ) { MarkIndexFree( pPool, indexToFree, 0 ); KMutexUnlock( &pPool->mutex ); } else { LOG( "%s(): Couldn't lock mutex", __FUNCTION__ ); assert( 0 ); } } }
void* PoolAlloc( MemPool* pPool ) { void* retval = 0; if ( pPool ) { if ( KMutexLock( &pPool->mutex, WAIT_FOREVER ) ) { uint32_t freeIndex = GetFreeIndex( pPool, 0 ); if ( freeIndex < pPool->numOfUnits ) { uint32_t sizeofUnit = pPool->backingBufferSize / pPool->numOfUnits; retval = ( ( uint8_t* )pPool->pBackingStore + ( sizeofUnit * freeIndex ) ); LOG( "%s(): Retval: %p ( index: %d )", __FUNCTION__, retval, freeIndex ); } KMutexUnlock( &pPool->mutex ); } else { LOG( "%s(): Couldn't lock mutex", __FUNCTION__ ); assert( 0 ); } } return retval; }
static void StartThread( void* arg ) { KMutex locks[NESTING_DEPTH - 1]; DonorThreadParams donorParams[ NESTING_DEPTH ]; TestData* pTestData = ( TestData* ) arg; for (uint32_t i = 0; i < NESTING_DEPTH - 1; i++) { char tmp[30]; bool workerMutexCreateResult = false; sprintf_s( tmp, sizeof(tmp), "Mutex %d", i ); workerMutexCreateResult = KMutexCreate( &locks[ i ], tmp ); } KMutexLock( &locks[0], WAIT_FOREVER ); ConsoleLogLine( "%s got lock, My Priority: %d", s_data.threads[0].threadName, KThreadGetPriority( &pTestData->threads[ 0 ] ) ); for ( uint32_t i = 1; i < NESTING_DEPTH; i++) { char name[16]; int thread_priority; snprintf (name, sizeof name, "thread %d", i); thread_priority = PRI_MIN + i * 3; donorParams[ i ].lockPair.first = i < NESTING_DEPTH - 1 ? locks + i : NULL; donorParams[ i ].lockPair.second = locks + i - 1; donorParams[ i ].i = i; donorParams[ i ].pThread = &pTestData->threads[ i ]; donorParams[ i ].pTestData = pTestData; KThreadCreateParams params = { .fn = DonorThreadFunction, .pStack = pTestData->stacks[ i ], .pThreadName = name, .stackSizeInBytes = sizeof( pTestData->stacks[ i ] ), .threadArg = &donorParams[i], .threadPriority = thread_priority }; ConsoleLogLine( "Starting %s with priority: %d", name, thread_priority ); TEST_ASSERT( KThreadCreate( &pTestData->threads[ i ], ¶ms ) ); /* ConsoleLogLine ("%s should have priority %d. Actual priority: %d.", name, thread_priority, KThreadGetPriority( &pTestData->threads[ i ] ) ); snprintf (name, sizeof name, "interloper %d", i); interloperParams[ i ].i = i; interloperParams[ i ].pThread = &pTestData->interloperThreads[ i ]; interloperParams[ i ].pTestData = pTestData; KThreadCreateParams paramsInterloper = { .fn = InterloperThreadFunction, .pStack = pTestData->interloperStacks[ i ], .pThreadName = name, .stackSizeInBytes = sizeof( pTestData->interloperStacks[ i ] ), .threadArg = &interloperParams[ i ], .threadPriority = thread_priority - 1, }; TEST_ASSERT( KThreadCreate( &pTestData->interloperThreads[ i ], ¶msInterloper ) ); */ } TEST_ASSERT_EQUAL_INT( NESTING_DEPTH - 1, pTestData->currentThreadIndexToRelease ); KMutexUnlock( &locks[ 0 ] ); /* ConsoleLogLine("%s finishing with priority %d.\n", KThreadGetName( &pTestData->threads[ 0 ] ), KThreadGetPriority( &pTestData->threads[ 0 ] ) ); */ TEST_ASSERT( KThreadJoin( &pTestData->threads[ 1 ] ) && KThreadJoin( &pTestData->interloperThreads[ 1 ] ) ); } static void TestPriorityDonateChain( void ) { TestData* pTestData = &s_data; pTestData->currentThreadIndexToRelease = 0; KThreadCreateParams startThread = { .fn = StartThread, .pStack = pTestData->stacks[ 0 ], .pThreadName = "StartThread", .stackSizeInBytes = THREAD_STACK_SIZE, .threadArg = pTestData, .threadPriority = PRI_MIN, }; pTestData->currentThreadIndexToRelease = 0; bool startThreadCreateResult = KThreadCreate( &pTestData->threads[ 0 ], &startThread ); TEST_ASSERT( startThreadCreateResult ); //Test ends when StartThread Ends bool waitForStartThreadEnd = KThreadJoin( &pTestData->threads[ 0 ] ); TEST_ASSERT( waitForStartThreadEnd ); } static void DonorThreadFunction( void *args ) { DonorThreadParams* pParams = ( DonorThreadParams* )args; if (pParams->lockPair.first) KMutexLock(pParams->lockPair.first, WAIT_FOREVER ); ConsoleLogLine( "%s priority %d, Actual priority: %d\n", KThreadGetName( pParams->pThread ), KThreadGetPriority( pParams->pThread ) ); TEST_ASSERT_EQUAL_INT( pParams->i - 1, pParams->pTestData->currentThreadIndexToRelease ); pParams->pTestData->currentThreadIndexToRelease = pParams->i; KMutexLock(pParams->lockPair.second, WAIT_FOREVER ); TEST_ASSERT_EQUAL_INT( NESTING_DEPTH - pParams->i, pParams->pTestData->currentThreadIndexToRelease ); pParams->pTestData->currentThreadIndexToRelease = NESTING_DEPTH - ( pParams->i + 1 ); KMutexUnlock(pParams->lockPair.second); /* ConsoleLogLine ("%s should have priority %d. Actual priority: %d\n", KThreadGetName( pParams->pThread ), (NESTING_DEPTH - 1) * 3, KThreadGetPriority( pParams->pThread ) ); */ if (pParams->lockPair.first) KMutexUnlock(pParams->lockPair.first); /* ConsoleLogLine("%s finishing with priority %d.\n", KThreadGetName( pParams->pThread ), KThreadGetPriority( pParams->pThread ) ); */ }