xStreamBufferReceive(…, portMAX_DELAY) Task Moved to Suspended and Never Wakes on Data

The same problem description but seems to be none stack overflows. I’ve read the topic:

And have checked stacks thoroughly. I added monitoring task which gathering all tasks info and checks unused stack remainder. uxTaskGetStackHighWaterMark() is called for every task including Timer and Idle tasks. And there are remainders everywhere. 49 or more stack words are untouched in stacks of every of total six tasks including timer and idle tasks.

FreeRTOS is running on single RISC-V QuingKe4F MCU core. RTOS port was taken from MCU manufacturer with almost none intervention but carefully checked.
Compiler is GCC. IDE is Eclipse.
What next step I need to debug the cause of xStreamBufferReceive task get suspended but not woken-up?

Before first entry, receiving task is in eReady state. After first entry while there are no data in stream buffer yet the state become eSuspended and buffer handle unit xTaskWaitingToReceive is holding receiving task handle.
I’m not sure should be receiving task eBlocked or @Suspended?
Oops! Actually I sure, it should be suspended:

eSuspended, /* The task being queried is in the Suspended state, or is in the Blocked state with an infinite time out. */

which is my case cause I’d asked portMAX_DELAY. So far, so good.
The problem manifests itself as follows:

  1. Stream buffer receiving task, upon a first entering xStreamBufferReceive() is changing it’s state to eSuspended. OK.
  2. While exectuting xStreamBufferReceive() first time, xTaskWaitingToReceive unit become set to receiving task handle. OK.
  3. While first call of sending task xStreamBufferSend() puts more bytes than buffer threshold is set for. So receiving task should wake up. But nope. Receiving task is staying suspended.
  4. Also after first call of xStreamBufferSend(), xTaskWaitingToReceive in stream buffer handle become NULL.
  5. Next calls for xStreamBufferSend() just filling the buffer but receiving task remains deadly suspended.

Here is Receiving task code:

void vUART_DMAtx(void *pvParameters) {
	(void) pvParameters;
	char Buff[xBufferSizeBytes];
	for (;;) {
		size_t Size = xStreamBufferReceive(xDebugMsgStream, (void* ) Buff, sizeof(Buff), portMAX_DELAY); //Wait for next message
		if (Size > 0) { //Sanity check for size of data requested for a transmission
			asm volatile ("NOP"); //Never reaching this
			//Some data need to be transferred
			//Blah Blah Blah
		} else {
			//Size of request is zero. Do nothing.
		}
	} //Repeat forever
}

Here is sending function which is called from usual RTOS tasks which are not an interrupts:

__attribute__((used)) int _write(int FileHandle, char *Data, int Size) {
	(void) FileHandle;
	vTaskSuspendAll();
	Size = xStreamBufferSend( xDebugMsgStream, Data, Size, 0 );
    ( void ) xTaskResumeAll();
	return Size;
}

Here is buffer definition:

//FreeRTOS Message buffer
uint8_t pucDbgMsgBufStor[xBufferSizeBytes]; //Debug message buffer storage area
StaticMessageBuffer_t xDbgMsgBufStruct; //Debug message buffer structure
StreamBufferHandle_t xDebugMsgStream; //Debug message buffer handle

There is buffer creation:

	xDebugMsgStream = xStreamBufferCreateStatic(xBufferSizeBytes, 1, pucDbgMsgBufStor, &xDbgMsgBufStruct); //Create background debug stream buffer for sending debug messages to UART

Receiving task is created static:

	xDebugUART = xTaskCreateStatic(vUART_DMAtx, (const char*) "DebugUART", DebugUART_STK_SIZE, (void*) 1, DebugUART_PRIO, puxDbgUARTstkBuf, &xDebugUART_TCB);

Receiving task should copy data into DMA buffer then initiate DMA transfer with an interrupt upon completion. DMA transfer it’s own is tested separately and is not enabled yet. DMA interrupt is not enabled too for stream buffer wake-up problem debug.
What can I do next to debug.

Just forgotten: If I set xTicksToWait for some other value, say 10, the code works as expected.
xStreamBufferReceive() function become unblocked by a timeout and the data are successfully flowing from UART Tx (if I’ll enable DMA and it’s ISR).

Just tested. If I’m sending intentionally at a start of receiving task, before the forever loop, like this:

	xStreamBufferSend(xDebugMsgStream, (const void*) HelloString, sizeof(HelloString) - 1, 0); //Send a hello to fill the buffer by first message

then stream buffer is containing the data before fist call of xStreamBufferReceive() receiver task.
And at first call, xStreamBufferReceive() produces non-zero output and the code continues normal UART transfer as expected.
After this first transfer, at second run of forever loop in receiving task, task state become eSuspended:

because there are no data in buffer yet. And receiving task is “subscribed” for the stream:

Seems to be good.
Then upon new data arrival, xStreamBufferSend() is called from one of the task:

Seems to be good, not from an ISR.
Upon a completion of xStreamBufferSend() the state of receiving task remaining eSuspended and the “subscription” for stream buffer notification is gone.
I’m frustrated:

Upd: In short, all seems to be correct except the receiver task kept suspended instead to be woken-up. What should make the task running? What should I pay attention to?

What is your code to send from the ISR? An ISR can’t call the xStreamBufferSend() function, but needs to all the FromISR version.

None stream buffer access is performed from an ISRs. The problem persists even if I didn’t enable any user ISR, only RTOS system timer ISR is running. Nevertheless, the calling of xStreamBufferSend() doesn’t woke-up the receiving task.

BTW wrapping xStreamBufferSend byvTaskSuspend/ResumeAll makes no sense.
xStreamBufferSend is thread safe, of course.

Nope. The description of stream buffer APIs is directly mentioning that buffer is intended to be used with one supplier one consumer. If there are more suppliers (or consumers) then the user is responsible for request serialization.
In my case _write() can be called from two different tasks with different priorities. So at some moment one _write() may be pre-empted by another. That is why I should use some kind of context switching block.
In first implementation I even used task critical section. One man on some RISC-V Telegram channel said that blocking an interrupts is too much and recommended to use vTaskSuspend/Resume instead.
Anyway, the problem persists. After calling _write() the data are in the buffer but data consuming task is suspended with no chance to wake because there is no link to it in buffer handle.

In short, everything correctly, except that the receiver task is still suspended instead of being woken up. What should make the task run? What should I pay attention to?

Ok - my bad, I missed somehow that you’re using it from multiple writers.

Actually I missed to emphasize that senders are several different tasks. It’s just a debug output and any task can print to debug channel.

Hi @Nikolay-Po,
Are there any tasks monopolizing CPU time that could be blocking the scheduler from task switching?

This is synthetic test project to prove the UART debug output is operating.
The priority of receiving task is highest. And two lower priority sender tasks are blinking by their diagnostic LEDs perfectly as expected.
So, no, there are none tasks blocking the receiving task.
Also, the receiving task is working if I set a buffer receive timeout other than port max delay.

Can you put a data breakpoint on xTaskWaitingToReceive to see what is setting it to NULL?

Good question. Due to inconsistent operation of data watchpoints, had to step through xStreamBufferSend() manually with assembler instruction stepping enabled.
Here is a result:

The “subscription” for stream buffer data arrival notifications is cleared at the line 924 of stream_buffer.c by the macro prvSEND_COMPLETED( pxStreamBuffer ). It seems to me normal because of a notification is sent and the task will “renew the subscription” next time the xStreamBufferReceive() is called when there will be no new data in the buffer.
But the problem is the receiving task is not resumed.

It seems to me the problem may be related somehow to this topic:

Also very interesting topic. Looks very similar to what I see except I’m not using interrupts.


The callstack looks too deep. Can you try increasing the stack size significantly?

Just heavily refactored the code, used dynamic allocation, descriptor queue and direct task notification.
Something is wrong with my FreeRTOS port. The queue is working but xTaskNonltifyGiveFromISR() and xTaskNotifyGet() are triggering only once. The second time the task is staying notified but suspended.
At what I need to point an attention to? Wh

Did you mean global, system stack, not the task stack itself? I’ve already increased it twice from 2048 to 4096 bytes in *.ld file.

I meant the task stack. Just for experiment, can you avoid using printf and call xStreamBufferSend directly instead of calling it from _write?

1 Like

Here is higher priority monitoring task:

volatile TaskStatus_t TaskState[8];
volatile uint32_t TaskStackRemainder[8] = { 0xFFFFFFFFul, 0xFFFFFFFFul, 0xFFFFFFFFul, 0xFFFFFFFFul, 0xFFFFFFFFul, 0xFFFFFFFFul, 0xFFFFFFFFul, 0xFFFFFFFFul };

void MonitorTask(void *Parameters) {
	(void) Parameters;
	TickType_t xLastWakeTime = xTaskGetTickCount();
	for (;;) {
		vTaskDelayUntil(&xLastWakeTime, 10); //Repeat regularly
		UBaseType_t NOT = uxTaskGetNumberOfTasks();
		uxTaskGetSystemState((TaskStatus_t*)TaskState, 8, NULL); //Gather an information about a tasks
		for (UBaseType_t TaskNum = 0; TaskNum < NOT; TaskNum++) { //Scan all tasks for stack spare space
			uint32_t TaskStackFree = uxTaskGetStackHighWaterMark(TaskState[TaskNum].xHandle);
			__AMOMINU_W(&TaskStackRemainder[TaskNum], TaskStackFree); //Get absolute minimum free stack value of given task
			if (TaskStackFree < 16) {
				for (;;) { //ToDo: Dead loop. Not for a release.
					asm volatile ("NOP");
					//Alarma! Stack is too small!
				}
			}
		}
	}
}

It collects task states and checks for stack remainders of every task by task watermark observation.
Here is the result of running for some time (when the buffer is already full with no motion):


The tasks are:

  • 0 - Monitor (the code above);
  • 1 - task1 (first writer);
  • 2 - IDLE;
  • 3 - task2 (second writer);
  • 4 - Tmr Svc;
  • 5 - DebugUART.

My own all four tasks are static.
I’ve tried to increase stack for all of them but no luck. The tasks are blinking by diagnostic LEDs flawlessly. But DebugUART task is staying eSuspended with usNotifyState==taskNOTIFICATION_RECEIVED.
Something is wrong with my port - notifications nor inside of stream nor direct task ones are not working - they are setting taskNOTIFICATION_RECEIVED but not resuming notification subscriber.