Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 11 Dec 2006 23:34:40 +0100 (CET)
From:      "Arne H. Juul" <arnej@pvv.ntnu.no>
To:        Kostik Belousov <kostikbel@gmail.com>
Cc:        freebsd-arch@freebsd.org, freebsd-java@freebsd.org
Subject:   Re: close() of active socket does not work on FreeBSD 6
Message-ID:  <Pine.LNX.4.62.0612112259050.12159@decibel.pvv.ntnu.no>
In-Reply-To: <20061211171115.GD311@deviant.kiev.zoral.com.ua>
References:  <Pine.LNX.4.62.0612111535280.32258@decibel.pvv.ntnu.no> <Pine.LNX.4.62.0612111552480.16908@decibel.pvv.ntnu.no> <20061211171115.GD311@deviant.kiev.zoral.com.ua>

next in thread | previous in thread | raw e-mail | index | archive | help
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.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.LNX.4.62.0612112259050.12159>