Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

strace: Any sense in `dup2(A, B); close(B)`?

I'm trying to understand a strace of an Java application server running in a oracle JVM.

I often see these lines:

[pid 10465] 23:04:59.658453 dup2(215, 274) = 274
[pid 10465] 23:04:59.658616 close(274)  = 0

In this case 215 is a UNIX socket:

java    10387 XXX  215u  unix 0xffff880037962cc0      0t0 153294021 socket

FD 274 is an open TCP socket.

These "call pairs" repeat multiple times with the same A socket over multiple minutes.

My understanding of dup2(A, B) is that it creates an file descriptor B pointing/refering to the same file/socket A, closing B first if it's still open.

Opengroup says

The dup2() function shall cause the file descriptor fildes2 to refer to the same open file description as the file descriptor fildes and to share any locks, and shall return fildes2. If fildes2 is already a valid open file descriptor, it shall be closed first, unless fildes is equal to fildes2 in which case dup2() shall return fildes2 without closing it.

My only guess so far is, that this a strange, unoptimized behaviour of the JVM. Isn't it? Which sense does it make.

If necessary, I'll add more context calls.

like image 827
try-catch-finally Avatar asked Jul 14 '14 21:07

try-catch-finally


1 Answers

This sequence provides a thread-safe way to close a socket.

dup2 allows to close a socket without releasing a file descriptor. This can be a lengthy operation due to untransmitted data and a long linger interval. dup2(A, B) is an atomic equivalent to

close(B);
fcntl(A, F_DUPFD, B);

i.e. B remains a valid descriptor at any time. Keeping the file descriptor valid is essential until all threads that have acquired this descriptor complete outstanding I/O operations.

fd being duplicated (215 in your case) is a special marker socket in shutdown state. It is created once for the only purpose of closing other sockets via dup2. Once dup2 is complete, any reads from the original fd (274) will return EOF and any writes to it will get an error.

Java maintains a use counter for each file descriptor. Threads increment this counter when acquiring a file descriptor and decrement it when they are done with I/O. As soon as use counter drops to 0, Java calls close to release the file descriptor and make it available to the OS.

Java NIO implementation uses the same technique to close files.
Though I haven't seen this pattern other than in JDK source code.

like image 122
apangin Avatar answered Oct 01 '22 02:10

apangin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!