2016-07-19 05:05 AM
lines in osPoolAlloc function:
index = pool_id->currentIndex + i;if (index >= pool_id->pool_sz) { index = 0;}must be replaced with:
index = (pool_id->currentIndex + i) % pool_id->pool_sz;2016-07-20 01:42 AM
I've decided to rewrite the whole function :)
void* osPoolAlloc( osPoolId pool_id )
{
if( pool_id == NULL ) return NULL;
uint32_t pool_sz = pool_id->pool_sz ;
uint32_t currentIndex = pool_id->currentIndex;
uint8_t * markers = pool_id->markers ;
void * result = NULL ;
int dummy = 0 ;
if (inHandlerMode()) {
dummy = portSET_INTERRUPT_MASK_FROM_ISR();
}
else {
vPortEnterCritical();
}
for( uint32_t i = 0; i < pool_sz; i++ ) {
if( markers[currentIndex] == 0 ) {
markers[currentIndex] = 1;
result = (void *)((uint32_t)(pool_id->pool) + (currentIndex * pool_id->item_sz));
currentIndex = (currentIndex + 1) % pool_sz;
for( ++i; i < pool_sz; i++ ) {
if( markers[ currentIndex ] == 0 ) break;
currentIndex = (currentIndex + 1) % pool_sz;
}
pool_id->currentIndex = currentIndex;
break;
}
currentIndex = (currentIndex + 1) % pool_sz;
}
if (inHandlerMode()) {
portCLEAR_INTERRUPT_MASK_FROM_ISR(dummy);
}
else {
vPortExitCritical();
}
return result;
}
2018-02-07 02:58 AM
Sorry about reviving an old topic, but the original poster is 100% correct. There is definitely a major bug in osPoolAlloc() in CMSIS_RTOS/cmsis_os.c . The bug is that when the block at index[0] is not marked as free, and the pool was previously full, the pool will fail to allocate other, already freed blocks. Steps to reproduce:
Faulty, original code - note that in the event of index > pool_sz, the index will be stuck at zero for the rest of the loop, if the marker[0] is not free:
for (i = 0; i < pool_id->pool_sz; i++) {
index = pool_id->currentIndex + i; if (index >= pool_id->pool_sz) { index = 0; } if (pool_id->markers[index] == 0) { pool_id->markers[index] = 1; p = (void *)((uint32_t)(pool_id->pool) + (index * pool_id->item_sz)); pool_id->currentIndex = index; break; }}Fixed code:
index = pool_id->currentIndex; // ADDED
for (i = 0; i < pool_id->pool_sz; i++) { // FAULTY LOGIC REMOVED index %= pool_id->pool_sz; // ADDED, will wrap index around the bounds if (pool_id->markers[index] == 0) { pool_id->markers[index] = 1; p = (void *)((uint32_t)(pool_id->pool) + (index * pool_id->item_sz)); pool_id->currentIndex = index; break; } index++; // ADDED }On another note, it is a bit wasteful to use full bytes to mark occupied blocks. A bitfield would have sufficed and would have required up to 8x less heap.