Hartmut wrote:
What if you just close the server socket (from an other task) ?
I’m afraid that doing so may lead to a crash. After the socket is closed, the heap will be reused for something else, while the task is still in an API, using a pointer to the socket.
There are checks in all API’s, as many as possible, but the API can not see that the memory space has been given back to the heap.
Hartmut wrote:
Or simply set a global restart flag before close to give the server
task an additional hint what to do on accept returning an error.
Yes like that, or use task-notify, or a semaphore.
The API’s FreeRTOS_recv()
and FreeRTOS_select()
can be interrupted from outside, by calling :
#if ( ipconfigSUPPORT_SIGNALS != 0 )
BaseType_t FreeRTOS_SignalSocket( Socket_t xSocket );
#endif
This feature was added for users of wolfSSL (Embedded SSL/TLS Library). That library has blocking calls to FreeRTOS_recv(), and it was not able to respond immediately to any event, only after receiving TCP data. Thanks to this signal, it could interrupt a call to FreeRTOS_recv()
, and respond to a button press or whatever event.
We could extend the usage of this signal to accept()
and other API’s, but I lack time. And also, it is not really compatible with BSD/Posix.
In my personal projects, I never have blocking calls for sockets, only polling. I let the task sleep ( block ) on a call to FreeRTOS_select()
( which can be signalled too ), or I have the task wait for a semaphore.
Here is a feature that is less known: you can have a socket signal a semaphore on any important event ( connected, disconnected, read, write, error ):
#if ( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
#define FREERTOS_SO_SET_SEMAPHORE ( 3 ) /* Used to set a user's semaphore */
#endif
SemaphoreHandle_t xServerSemaphore;
xServerSemaphore = xSemaphoreCreateBinary();
/* Connect a socket to a semaphore. */
FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SET_SEMAPHORE, ( void * ) &xServerSemaphore, sizeof( xServerSemaphore ) );
Now you can write a loop for the task:
/* Let the task wake-up every 2 seconds at least to do some regural tasks. */
TickType_t xReceiveTimeOut = pdMS_TO_TICKS( 2000 );
for( ;; )
{
xSemaphoreTake( xServerSemaphore, xReceiveTimeOut );
/* Now check the socket with non-blocking calls. */
}
With this method, any other task can get the attention of my task immediately, by signalling the semaphore.
I wrote several big TCP servers with this technique. There is a minor overhead when calling recvv()
in a non-polling way.
Summary: you can either use FreeRTOS_select()
, which can be signalled, or use a semaphore, which can be signalled from any other task as well.
Another feature you may want to check is ipconfigUSE_CALLBACKS
, which allows specific call-backs.