Mon 14 Mar 2011 09:10:57 PM UTC, original submission:
When multiple threads are sending over the same UDP socket (using sendto()), there is a race condition in tcpip_apimsg(). What happens is that one thread (thread 1) enters tcpip_apimsg() and posts to the tcpip thread. The tcpip thread then runs the do_send function and signals the conn->op_completed semaphore. Then the tcpip thread goes back to blocking on the mbox.
At this point, if a different thread (thread 2) is selected to run, the conn->op_completed semaphore is already set. That means that when thread 2 calls sendto() and enters tcpip_apimsg(), it posts the operation to the mbox and then waits on the semaphore. Since the semaphore is already signalled, it returns immediately. Then, when the tcpip thread runs the operation, it corrupts the stack of thread 2.
I fixed this issue by adding a semaphore to struct lwip_sock, and locking it while calling netconn_send() in lwip_sendto(). I'm not sure if this is the best way to do it though.
I'm not sure what the correct behaviour is here. Sending to a UDP socket from multiple threads works on other platforms. However, it is not difficult for the application to manage the locking properly. The locked region would be larger than if the locking were done in lwIP itself.
It seems like sending to / receiving from a UDP socket from multiple threads should work since UDP sends datagrams; I wouldn't expect it to work with TCP since the stream would get garbled. Note that I didn't try receiving from multiple threads, but I assume it works in a similar way.
|