close() of active socket does not work on FreeBSD 6
Arne H. Juul
arnej at pvv.ntnu.no
Mon Dec 11 14:40:42 PST 2006
On Mon, 11 Dec 2006, Kostik Belousov wrote:
> On Mon, Dec 11, 2006 at 04:07:09PM +0100, Arne H. Juul wrote:
>> Looking at the Java VM source code it does some tricks with dup2() to
>> reopen the close()'d filedescriptor, making it point to a filedescriptor
>> that's pre-connected to a closed socket.
>>
>> A small C program that duplicates this (using pipes to make it a bit
>> simpler) follows. I'm not sure if any standards demand that this
>> works like it used to on FreeBSD 4 / libc_r, but since Java uses it it
>> would be really nice if this could be made to work in FreeBSD 6 (libthr
>> and libpthread). Or maybe somebody has another suggestions on how to
>> implement the Java close() semantics?
>
> I think that -arch@ is proper ML to discuss the issue.
>
> Your test example hangs becase read() takes one more hold count on the
> file descriptor operated upon. As result, when calling close, f_count
> of the rpipe (aka p[0]) is 2, close() decrements it, f_count becomes
> 1. Since f_count > 0, fdrop_locked simply returns instead of calling
> fo_close (see kern_descrip.c).
>
> I cannot find the statement in SUSv3 that would require interruption of
> the read() upon close() from another thread; this looks like undefined
> behaviour from the standard point of view.
The best authority I've found says that the standards are silent (so
the current FreeBSD 6 behaviour is allowed), I'm asking whether it is
best practice and why it's changed since FreeBSD 4.
> I think that JVM is more appropriate place for fix, but others may have
> different view point.
If it was just the JVM I would agree, but any threaded program that uses
blocking I/O in some threads will probably need the same kind of handling
at some point. And if you think about what that handling looks like,
it's not exactly pretty:
* when calling any potentially blocking system call (read/readv,
write/writev, recv/recvfrom/recvmsg, send/sendto/sendmsg, accept,
connect, poll, select, maybe others that I didn't think of) the
application must:
** take a mutex
** remember in some structure (linked list or similar) keyed off
the file descriptor that "this thread will now do blocking I/O"
** release the mutex
** perform the actual operation
** take the mutex again
** check if the operation was interrupted in a special way, if so
return with EBADF
** release the mutex
* instead of calling close() and dup2() the application must:
** take the mutex
** for each thread in the FD-associated structure, interrupt it
in some special way (I'm guessing that setting a special flag
and then sending SIGIO should work).
** actually do the close() / dup2()
** release the mutex
This is exactly the sort of issue that should be solved by the
thread library / kernel threads implementation and not in every
threaded application that needs it, in my view.
- Arne H. J.
More information about the freebsd-java
mailing list