Reasons for only 1 task stuck on xQueueReceive

I am using the same sort of queue i/o in many places in my code, and all was working (RT1050 from NXP).
Updating my stack from NXP SDK 2.10 to 2.11, which also updates FreeRTOS from V10.4.3 to V10.4.3 LTS Patch 2.

With this update, just one of my many queues is getting stuck, so same method (I think) works in most places except one.

rando_task sends a message to audio_task (both at pri 3), then waits for audio_task to message back via an EventGroup.
In the last version, this was working fine. I have plenty of RTOS stack headroom.

Basic code:

static void audio_task(void *pvParameters){
  BaseType_t x_status;
  audio_queue_event_t cmd_event;
  if (audio_events == NULL){
    audio_events = xEventGroupCreate();
  }
  x_audio_queue = xQueueCreate(3, sizeof(audio_queue_event_t));

  //edit for posterity - this is where the freeze happened - thanks Richard :
  buzzer(SOUND_PWRUP); //(added after the fact)

  for (;;) {
    x_status = xQueueReceive( x_audio_queue,  &cmd_event, portMAX_DELAY );
    if( x_status == pdPASS ) {
      buzzer(cmd_event.sound_clip_e);
      xEventGroupSetBits(audio_events, ON_SOUND_STARTED);
    }
  }
}

For ^^^, x_audio_queue was successfully created and allocated, same with audio_events group.

The caller that gets stuck (also on a task @ pri 3:

void audio_play_sound(soundclip_enum_t sc){
  EventBits_t event_bits;
  BaseType_t x_status;
  static audio_queue_event_t cmd_event;
  cmd_event.sound_clip_e = sc;

  x_status = xQueueSendToBack(x_audio_queue, &cmd_event, 0);
  if (x_status != pdPASS) {
    return;
  }
  event_bits = xEventGroupWaitBits(audio_events, ON_SOUND_STARTED, pdTRUE, pdFALSE, portMAX_DELAY);
  if ((event_bits & ON_SOUND_STARTED) != ON_SOUND_STARTED){
    //    return kStatus_Fail; //shouldn't happen
  }
}

Any ideas on what I may be doing that could cause a break between FreeRTOS/SDK versions? I am doing the same queue->eventgroup pingpong kind of wait in other areas of code without issue…

What I am seeing is that the audio_task never gets out of the xQueueReceive (so it doesn’t even try to call the buzzer function).

Tried also increasing audio_task’s priority to 4, but that doesn’t help.

Does the sending task wait to make sure the queue exists before sending?

1 Like

Added extra waitgroup check per your suggestion.

Waitgroup waits & exits upon queue creation as expected, but deadlock still exists in the actual xQueueReceive .

Pausing the debugger during deadlock shows the following:
Heap is 90% used, so still a fair amount of headroom, and audio_task is the only one “Blocked”, IDLE task is “Running”, and every other task is “Suspended”.

uxDeletedTasksWaitingCleanUp == 0…

Maybe I’m missing something, but if everythign is suspended, there should be nothing blocking audio_task from waking up and taking the x_audio_queue item intended for it, no?

That shows it is locked, but not what on.Is it o the waiting to receive list?

One thing that can sometimes cause this sort of issue is interrupts above the acceptable priority.

Do you have configASSERT defined to trap on problems being detected?

configAssert is currently:


/* Define to trap errors during development. */
#define configASSERT(x) if((x) == 0) {taskDISABLE_INTERRUPTS(); for (;;);}

so i assume it’d be stopping here if there were some assertion? Or do I need to do further?

The other thing I see from the above screenshot state is that i have 1 item in my queue, and in my audio_task, i have a breakpoint on the line after the xQueueReceive which never gets hit.

Put some asserts or checks in the code to catch the else cases on x_Status == pdPass. If that condition every fails for whatever reasons, your control flow will get out of sync.

1 Like

Added these, none of the asserts are getting hit, and still stuck waiting for xQueueReceive in the audio_task:

void audio_task_startup(void){
  if (audio_events == NULL){
    audio_events = xEventGroupCreate();
  }
  if (xTaskCreate(audio_task, "audio_task", 8000, NULL, 3 , &audio_handle) != pdPASS){
    assert(0);
  }
  EventBits_t event_bits = xEventGroupWaitBits(audio_events, ON_SOUND_STARTED, pdTRUE, pdFALSE, portMAX_DELAY);
  if ((event_bits & ON_SOUND_STARTED) != ON_SOUND_STARTED){
    assert(0);
  }
}
void audio_play_sound(soundclip_t sc){
  static audio_queue_event_t cmd_event;
  cmd_event.sound_clip = sc;

  BaseType_t x_status = xQueueSendToBack(x_audio_queue, &cmd_event, 0);
  if (x_status != pdPASS) {
    assert(0);
  }
  EventBits_t event_bits = xEventGroupWaitBits(audio_events, ON_SOUND_STARTED, pdTRUE, pdFALSE, portMAX_DELAY);
  if ((event_bits & ON_SOUND_STARTED) != ON_SOUND_STARTED){
    assert(0);
  }
}
static void audio_task(void *pvParameters){
  BaseType_t x_status;
  audio_queue_event_t cmd_event;
  x_audio_queue = xQueueCreate(3, sizeof(audio_queue_event_t));
  xEventGroupSetBits(audio_events, ON_SOUND_STARTED);

  //edit for posterity - this is where the freeze happened - thanks Richard :
  buzzer(SOUND_PWRUP); //(added after the fact)

  for (;;) {
    x_status = xQueueReceive( x_audio_queue,  &cmd_event, portMAX_DELAY );
    if( x_status == pdPASS ) {
      buzzer(cmd_event.sound_clip);
      xEventGroupSetBits(audio_events, ON_SOUND_STARTED);
    } else {
      assert(0);
    }
  }
}

Your play function still doesn’t show a check that the queue is created before posting to it. With configASSERT that should normally assert. Make real sure it is posting to the same queue as you are taking from.

As I mention, check the list of task waiting to make sure it is there. My guess is somehow it is waiting on something else.

That was a good comment afterall @richard-damon , it seems the buzzer() function itself is locking the audio_task, not my FreeRTOS pingponging…

Thanks again

Your play function still doesn’t show a check that the queue is created before posting to it. With configASSERT that should normally assert. Make real sure it is posting to the same queue as you are taking from.
As I mention, check the list of task waiting to make sure it is there. My guess is somehow it is waiting on something else.

The queue was successfully created, but I was wondering - how do you confirm that? I suppose just comparing x_audio_queue against NULL… (that’s how i was manually checking via the debugger at least)

Yes, check the handle, or better, create it before starting the scheduler so you KNOW it has to be there.

1 Like

If this is a reproducable requirement for the problem to show, it would be interesting to see a diff between the two releases. My suspicion, though, it’s rather a side effect in something else in the SDK that causes the problem.

Correct, something in the SDK audio driver broke- contacted NXP directly on that one