@shayan_mukhtar, thank you for reporting this.
First a short explanation: every socket has an RX and a TX stream, i.e. for reception and for the transmission of data. These are independent objects.
These streams are only created when needed. And like @rtel mentioned: “a socket can only have one reader and one writer”, which may be the same task.
An RX stream uses 3 pointers: uxTail - uxHead - uxFront
A user task reads from the RX stream with FreeRTOS_recv()
The IP-task writes to this stream in a “private” function lTCPAddRxdata()
A TX stream also uses 3 pointers: uxTail - uxMid - uxHead
A user task writes to the TX stream with FreeRTOS_send()
The IP-task reads from the TX stream in a private function prvTCPPrepareSend()
.
The problem that you describe has to do with the RX-stream, right?
Data has been received and is being added to the RX stream when lTCPAddRxdata()
calls uxStreamBufferAdd()
.
Theory: just before uxFront
is advanced, there is a context switch and FreeRTOS_recv()
compares uxTail with uxFront, and concludes erroneously that the RX socket has no space.
I think this was not reported before because most developers assign a different (usually higher) priority to the IP-task.
In your project the IP-task and the user task seem to have the same priority and the clock tick will lead to a task switch, correct?
You wrote:
- The read from the socket works, and the tail pointer is incremented
Right, that happens in FreeRTOS_recv()
- If in that same task a write is attempted to the socket, in the window update logic, the front pointer is now behind the tail pointer
I don’t understand this. Writing to a socket with FreeRTOS_send()
has nothing to do with reading from a socket. uxFront
only plays a role in the RX stream.
The only thing where the user task reads uxFront is here in uxStreamBufferFrontSpace()
, which is called here:
/* We had reached the low-water mark, now see if the flag
* can be cleared */
size_t uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
if( uxFrontSpace >= pxSocket->u.xTCP.uxEnoughSpace )
{
pxSocket->u.xTCP.bits.bLowWater = pdFALSE;
pxSocket->u.xTCP.bits.bWinChange = pdTRUE;
}
The “the window update logic” is performed by the IP-task. Seen from the IP-task, the value of uxFront
is up-to-date.
- This causes the stack to erroneously state the TCP receive window is 0
In case the tasks have equal priority and when preemption / time-slicing is enabled.
How easy is it for you to replicate the problem?
If it occurs easily you could try to suspend the scheduler while updating uxHead
and uxFront
+ vTaskSuspendAll();
+ {
if( uxOffset == 0U )
{
/* ( uxOffset == 0 ) means: write at uxHead position */
uxNextHead += uxCount;
if( uxNextHead >= pxBuffer->LENGTH )
{
uxNextHead -= pxBuffer->LENGTH;
}
pxBuffer->uxHead = uxNextHead;
}
if( xStreamBufferLessThenEqual( pxBuffer, pxBuffer->uxFront, uxNextHead ) != pdFALSE )
{
/* Advance the front pointer */
pxBuffer->uxFront = uxNextHead;
}
+ }
+ xTaskResumeAll();
Thanks