Are in FreeRTOS TCP the TCP/IP Socket ThreadSafe?

I try to understood the FreeRTOS TCP/IP Sockets and have seen, that the IP-Task copy the context of the frame in a Streambuffer. The Application task read the data with the functions FreeRTOS_recv from the streambuffer.
But there I have never found a Semaphore, vTaskSuspendAll or taskENTER_CRITICAL.
How is the Synchronization done? What happends if IP-Task write to the StreamBuffer and is interrupted by the Applicationtask?

You can only send to a TCP socket from a single task, and likewise you can only receive from it in a single task, but those two tasks do not need to be the same task. You cannot send to (or receive from) a socket from more than one task though - doing so would not make much sense as sockets are stream based and writing to a socket from multiple tasks would lead to garbled data just like writing to a serial port from more than one task would lead to garbled data.

Yes, this I understood. But this isn’t my Question.
The Application task read with the functions FreeRTOS_recv the TCP data from the streambuffer. If the in the “IP-Task” from FreeRTOS TCP IP a frame is recived, this will be added to the Streambuffer over the functions
prvIPTask → prvHandleEthernetPacket → prvProcessEthernetPacket → prvProcessIPPacket → xProcessReceivedTCPPacket → prvTCPHandleState → prvStoreRxData → lTCPAddRxdata → uxStreamBufferAdd

What I understood is, that the Streambuffer isn’t ThreadSave. But how is the Streambuffer Synchonisated between Application Task and IP-Task?

I know it is confusing because we use the same name for both, but the stream buffer used by the TCP/IP stack is not the same implementation as the stream buffer provided by the kernel. The TCP stack’s is really for internal use by the stack, and is, if I recall correctly, lockless. It is not safe for more than one task to read from it at once, or for more than one task to write to it at once, but it is safe for a different task to do the reading as that doing the writing. That is the source of the same restriction on use of the sockets themselves.

Did I answer this time? Let me know if not.

The stream buffer used by +TCP is essentially the same as the public stream buffer, except that the latter has many more options, and if you want you can use it in a blocking and/or synchronised way.

@rtel wrote:

The TCP stack’s is really for internal use by the stack,
and is, if I recall correctly, lockless

Indeed, there are no locks involved. When FreeRTOS_recv() or FreeRTOS_send() must block, they will use the event group that belongs to the socket. So when FreeRTOS_recv() finds an empty RX stream buffer, it may block, depending on the socket options (see FREERTOS_SO_RCVTIMEO and FREERTOS_SO_SNDTIMEO).

As Richard pointed out, you don’t have to worry about synchronisation between application and IP-stack, as long as there is a single reading task, and a single task that writes to the socket. The reason is that the two tasks do not alter common indexes.

This is the essence of a stream buffer:

  volatile size_t uxTail;   /**< next position to read, owned by the reader. */
  volatile size_t uxHead;   /**< next position write, owned by the writer. */
  uint8_t ucArray[ COUNT ]; /**< The buffer */

When uxTail equals uxHead, the buffer is empty. When they are not equal, the buffer contains data.

  • The reading task will change the value of uxTail until it equals uxHead.
  • The writing task will change the value of uxHead, until it becomes uxTail-1.

A buffer of COUNT elements can contain at most COUNT-1 bytes. So when a buffer is full, uxHead is just 1 position behind uxTail.

There is one important rule: first access the data in ucArray, and then update the index.

If all these conditions are met, the stream buffer doesn’t need any synchronisation, such as a mutex or a critical section. That is the elegance of it.

Thanks. This is the andswer of my Questions.