close() of active socket does not work on FreeBSD 6

Kostik Belousov kostikbel at gmail.com
Mon Dec 11 09:11:26 PST 2006


On Mon, Dec 11, 2006 at 04:07:09PM +0100, Arne H. Juul wrote:
> On Mon, 11 Dec 2006, 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?
> 
> Anyway, the following C program works as intended on FreeBSD 4,
> hangs on FreeBSD 6 (amd64), compiled with:
> 	 cc -Wall -pthread read_dup2.c -o read_dup2
> 
> 
> #include <fcntl.h>
> #include <stdlib.h>
> #include <stdio.h>
> #include <unistd.h>
> #include <pthread.h>
> 
> int p[2];
> 
> void *run(void *arg) {
>   ssize_t res;
>   char tmp[128];
>   fprintf(stderr, "reading...\n");
>   res = read(p[0], tmp, sizeof(tmp));
>   fprintf(stderr, "read result: %d\n", (int)res);
>   if (res < 0) {
>     perror("read");
>   }
>   return arg;
> }
> 
> int main(int argc, char **argv) {
>   pthread_t t;
>   int d = open("/dev/null", O_RDONLY);
>   if (pipe(p) != 0) {
>     perror("pipe");
>     return 1;
>   }
>   if (pthread_create(&t, NULL, run, NULL) != 0) {
>     perror("thread create");
>     return 1;
>   }
>   sleep(1);
>   d = open("/dev/null", O_RDONLY);
>   if (d < 0) {
>     perror("open dev null");
>     exit(1);
>   }
>   if (dup2(d, p[0]) < 0) {
>     perror("dup2");
>     exit(1);
>   }
>   if (pthread_join(t, NULL) != 0) {
>     perror("thread join");
>     exit(1);
>   }
>   return 0;
> }

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.

I think that JVM is more appropriate place for fix, but others may have
different view point.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 187 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-arch/attachments/20061211/2824f33d/attachment.pgp


More information about the freebsd-arch mailing list