Re: Expected result when racing listen(2) on two sockets bound to the same address
From: Kirill Tkhai <hidden>
Date: 2018-05-23 12:44:31
Also in:
lkml
Hi, On 23.05.2018 14:15, Alexander Kurtz wrote:
[Please keep me CC'ed; I'm not subscribed to the list]
Hi!
The program shown below (also available at [0]) does the following:
* Create two sockets
* Enable SO_REUSEADDR on both
* Bind both sockets to [::1]:12345
* Spawn two threads which both call listen(2) on one socket each
* Check that at least one thread succeeded
Unfortunately, when running this program on Linux 4.16, it is sometimes
possible that neither thread succeeds in calling listen(2):
$ uname -a
Linux shepard 4.16.0-1-amd64 #1 SMP Debian 4.16.5-1 (2018-04-29) x86_64 GNU/Linux
$ time make
cc -Wall -Wextra -pedantic -Werror -O3 listenrace.c -lpthread -o listenrace
for i in `seq 10000`; do ./listenrace; done
listenrace: listenrace.c:58: main: Assertion `result1 == 0 || result2 == 0' failed.
Aborted
listenrace: listenrace.c:58: main: Assertion `result1 == 0 || result2 == 0' failed.
Aborted
listenrace: listenrace.c:58: main: Assertion `result1 == 0 || result2 == 0' failed.
Aborted
real 0m8.201s
user 0m6.801s
sys 0m2.141s
$
As can be seen, on 3 runs (out of 10000) calling listen(2) failed in
*both* threads. Is this to be expected (i.e. "don't do this then") or
could this be some race condition in the Linux kernel?
At the first sight, it is in kernel and is expected:
inet_csk_listen_start()
{
/* There is race window here: we announce ourselves listening,
* but this transition is still not validated by get_port().
* It is OK, because this socket enters to hash table only
* after validation is complete.
*/
inet_sk_state_store(sk, TCP_LISTEN);
if (!sk->sk_prot->get_port(sk, inet->inet_num)) {
}
CC netdev.
Kirill