Priority inheritance not working as expected

alexanderw2 wrote on Thursday, January 28, 2016:

Hi, I’m using a STM32F429I-DISCO board with FreeRTOS V8.2.1 and am trying to understand how scheduling and priority inheritance work when using mutexes and queues. I’m using the BSP_LCD_DisplayStringAtLine() function to ouput what line just got executed or will get executed next.

The output:

high
high before take mutex 1
high after take mutex 1
high before receive
medium
medium before take mutex 1
low
low before take mutex 2
low before give mutex 1

There’s no more output, but I’d expect the next lines to be

medium after take mutex 1
medium before send queue 1
high before send

Why doesn’t FreeRTOS switch back to the medium priority task, after it got blocked by the xSemaphoreTake( Mutex_1, portMAX_DELAY) call and the Mutex_1 was given in the low priority task?

Thanks

int i = 0;

uint32_t data[]={1,2,3,4};
static void high (void *)
{
	BSP_LCD_DisplayStringAtLine (i++, (uint8_t *) "high");
	BSP_LCD_DisplayStringAtLine (i++, (uint8_t *) "high before take mutex 1");
	xSemaphoreTake( Mutex_1, portMAX_DELAY);
	BSP_LCD_DisplayStringAtLine (i++, (uint8_t *) "high after take mutex 1");
	for( int * ptr = (int*)data; *ptr <= 4; ++ptr)
	{
		BSP_LCD_DisplayStringAtLine (i++, (uint8_t *) "high before receive");
		xQueueReceive(	Queue_1, ptr, portMAX_DELAY);
		BSP_LCD_DisplayStringAtLine (i++, (uint8_t *) "high before send");
		xQueueSend( 	Queue_2, ptr, portMAX_DELAY);
	}
	vTaskSuspend(0);
}

static void medium( void *x)
{
	BSP_LCD_DisplayStringAtLine (i++, (uint8_t *) "medium");
	char *c;
	uint32_t tmp[1];
	for( c="012345";*c != 0 ;++c)
	{
		BSP_LCD_DisplayStringAtLine (i++, (uint8_t *) "medium before take mutex 1");
		xSemaphoreTake( Mutex_1, 	portMAX_DELAY);
		BSP_LCD_DisplayStringAtLine (i++, (uint8_t *) "medium after take mutex 1");
		*tmp = *c++;
		BSP_LCD_DisplayStringAtLine (i++, (uint8_t *) "medium before send queue 1");
		xQueueSend( Queue_1, tmp, 	portMAX_DELAY);
		*tmp = *c++;
		BSP_LCD_DisplayStringAtLine (i++, (uint8_t *) "medium before send queue 1");
		xQueueSend( Queue_1, tmp, 	portMAX_DELAY);
		BSP_LCD_DisplayStringAtLine (i++, (uint8_t *) "medium before take mutex 2");
		xSemaphoreTake( Mutex_2, 	portMAX_DELAY);
		BSP_LCD_DisplayStringAtLine (i++, (uint8_t *) "medium before give mutex 1");
		xSemaphoreGive( Mutex_1);
		BSP_LCD_DisplayStringAtLine (i++, (uint8_t *) "medium before give mutex 2");
		xSemaphoreGive( Mutex_2);
	}
}
uint32_t target[10];
static void low( void *x)
{
	BSP_LCD_DisplayStringAtLine (i++, (uint8_t *) "low");
	for( uint32_t *data = target;*data <= 9;data++)
	{
		BSP_LCD_DisplayStringAtLine (i++, (uint8_t *) "low before take mutex 2");
		xSemaphoreTake( Mutex_2, portMAX_DELAY);
		BSP_LCD_DisplayStringAtLine (i++, (uint8_t *) "low before give mutex 1");
		xSemaphoreGive( Mutex_1);
		BSP_LCD_DisplayStringAtLine (i++, (uint8_t *) "low after give mutex 1");
		BSP_LCD_DisplayStringAtLine (i++, (uint8_t *) "low before receive queue 2");
		while(pdTRUE==xQueueReceive( Queue_2, data++, portMAX_DELAY))
			/* do_nothing */;
		BSP_LCD_DisplayStringAtLine (i++, (uint8_t *) "low before take mutex 1");
		xSemaphoreTake( Mutex_1, portMAX_DELAY);
		BSP_LCD_DisplayStringAtLine (i++, (uint8_t *) "low before give mutex 2");
		xSemaphoreGive( Mutex_2);
	}
	vTaskSuspend(0);
}

rtel wrote on Thursday, January 28, 2016:

As far as I can see - and its not that easy to follow - your low priority task is attempting to give mutex 1 when mutex 1 is being held by the high priority task. Stepping into the code, or pausing the debugger, will probably show you stopped on the following line:

/* A task can only have an inherited priority if it holds the mutex.
If the mutex is held by a task then it cannot be given from an
interrupt, and if a mutex is given by the holding task then it must
be the running state task. */
configASSERT( pxTCB == pxCurrentTCB );

alexanderw2 wrote on Saturday, January 30, 2016:

Thanks for the quick response.

It was assumed that Mutexes could be given back by a task other than the one that took it. Commenting out the configASSERT() “fixes” it, as well as switching to a binary semaphore. I’ll have to ask in class why this unsupported way of using mutexes was used.