diff options
author | Elliott Hughes <enh@google.com> | 2012-09-28 15:53:29 -0700 |
---|---|---|
committer | Brian Carlstrom <bdc@google.com> | 2012-10-03 17:15:29 -0700 |
commit | b2e6be1cc1d375ca2fc28ee1fdfc10c0adc2554d (patch) | |
tree | 6e906dd3bafe851b3cf050e1744aa771e8ad181b | |
parent | 77b2088858b199e60002bfb2acb7a883c6aba82a (diff) | |
download | libcore-b2e6be1cc1d375ca2fc28ee1fdfc10c0adc2554d.zip libcore-b2e6be1cc1d375ca2fc28ee1fdfc10c0adc2554d.tar.gz libcore-b2e6be1cc1d375ca2fc28ee1fdfc10c0adc2554d.tar.bz2 |
Rewrite NIO Pipe to use socketpair(2).
Our Pipe originally used socket(2) to create AF_INET/AF_INET6
sockets. This was clearly a bad idea.
I rewrote it to use socketpair(2) and AF_UNIX, but this was
before the big "expose POSIX" rewrite, so it required a bunch
of hacks in the native code, so I went with pipe(2) instead.
The trouble with pipe(2) is that we end up using FileChannel
to implement the Pipe.SinkChannel and Pipe.SourceChannel, but
the kernel won't wake a read(2) on a pipe if another thread
calls close(2) on it, so we started failing interrupt tests.
This (final?) rewrite is hopefully the best of all worlds:
we don't have any INTERNET permission needs, the code is as
simple as the pipe(2) code, and interruption works.
Bug: 7084342
Bug: 2735373
Bug: http://code.google.com/p/android/issues/detail?id=9431
(cherry picked from commit 3218082325b6b8713a8ac15731482e3da86a7df9)
Change-Id: Ib92cdf8c818f6bba1f00e191f1b624ce9e693754
-rw-r--r-- | luni/src/main/java/java/nio/PipeImpl.java | 46 | ||||
-rw-r--r-- | luni/src/main/java/java/nio/SelectorProviderImpl.java | 2 | ||||
-rw-r--r-- | luni/src/main/java/java/nio/SocketChannelImpl.java | 9 | ||||
-rw-r--r-- | luni/src/main/java/libcore/io/BlockGuardOs.java | 6 | ||||
-rw-r--r-- | luni/src/main/java/libcore/io/ForwardingOs.java | 1 | ||||
-rw-r--r-- | luni/src/main/java/libcore/io/Os.java | 1 | ||||
-rw-r--r-- | luni/src/main/java/libcore/io/Posix.java | 1 | ||||
-rw-r--r-- | luni/src/main/native/libcore_io_Posix.cpp | 10 |
8 files changed, 47 insertions, 29 deletions
diff --git a/luni/src/main/java/java/nio/PipeImpl.java b/luni/src/main/java/java/nio/PipeImpl.java index 50028f4..d4dde3b 100644 --- a/luni/src/main/java/java/nio/PipeImpl.java +++ b/luni/src/main/java/java/nio/PipeImpl.java @@ -19,8 +19,8 @@ package java.nio; import java.io.Closeable; import java.io.FileDescriptor; import java.io.IOException; -import java.nio.channels.FileChannel; import java.nio.channels.Pipe; +import java.nio.channels.SocketChannel; import java.nio.channels.spi.SelectorProvider; import libcore.io.ErrnoException; import libcore.io.IoUtils; @@ -34,13 +34,16 @@ final class PipeImpl extends Pipe { private final PipeSinkChannel sink; private final PipeSourceChannel source; - public PipeImpl() throws IOException { + public PipeImpl(SelectorProvider selectorProvider) throws IOException { try { - FileDescriptor[] fds = Libcore.os.pipe(); - // Which fd is used for which channel is important. Unix pipes are only guaranteed to be - // unidirectional, and indeed are only unidirectional on Linux. - this.sink = new PipeSinkChannel(fds[1]); - this.source = new PipeSourceChannel(fds[0]); + FileDescriptor fd1 = new FileDescriptor(); + FileDescriptor fd2 = new FileDescriptor(); + Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd1, fd2); + + // It doesn't matter which file descriptor we use for which end; + // they're guaranteed to be indistinguishable. + this.sink = new PipeSinkChannel(selectorProvider, fd1); + this.source = new PipeSourceChannel(selectorProvider, fd2); } catch (ErrnoException errnoException) { throw errnoException.rethrowAsIOException(); } @@ -54,27 +57,14 @@ final class PipeImpl extends Pipe { return source; } - /** - * FileChannelImpl doesn't close its fd itself; it calls close on the object it's given. - */ - private static class FdCloser implements Closeable { - private final FileDescriptor fd; - private FdCloser(FileDescriptor fd) { - this.fd = fd; - } - public void close() throws IOException { - IoUtils.close(fd); - } - } - private class PipeSourceChannel extends Pipe.SourceChannel implements FileDescriptorChannel { private final FileDescriptor fd; - private final FileChannel channel; + private final SocketChannel channel; - private PipeSourceChannel(FileDescriptor fd) throws IOException { - super(SelectorProvider.provider()); + private PipeSourceChannel(SelectorProvider selectorProvider, FileDescriptor fd) throws IOException { + super(selectorProvider); this.fd = fd; - this.channel = NioUtils.newFileChannel(new FdCloser(fd), fd, O_RDONLY); + this.channel = new SocketChannelImpl(selectorProvider, fd); } @Override protected void implCloseSelectableChannel() throws IOException { @@ -104,12 +94,12 @@ final class PipeImpl extends Pipe { private class PipeSinkChannel extends Pipe.SinkChannel implements FileDescriptorChannel { private final FileDescriptor fd; - private final FileChannel channel; + private final SocketChannel channel; - private PipeSinkChannel(FileDescriptor fd) throws IOException { - super(SelectorProvider.provider()); + private PipeSinkChannel(SelectorProvider selectorProvider, FileDescriptor fd) throws IOException { + super(selectorProvider); this.fd = fd; - this.channel = NioUtils.newFileChannel(new FdCloser(fd), fd, O_WRONLY); + this.channel = new SocketChannelImpl(selectorProvider, fd); } @Override protected void implCloseSelectableChannel() throws IOException { diff --git a/luni/src/main/java/java/nio/SelectorProviderImpl.java b/luni/src/main/java/java/nio/SelectorProviderImpl.java index 03003fe..b7c34e8 100644 --- a/luni/src/main/java/java/nio/SelectorProviderImpl.java +++ b/luni/src/main/java/java/nio/SelectorProviderImpl.java @@ -34,7 +34,7 @@ public final class SelectorProviderImpl extends SelectorProvider { } public Pipe openPipe() throws IOException { - return new PipeImpl(); + return new PipeImpl(this); } public AbstractSelector openSelector() throws IOException { diff --git a/luni/src/main/java/java/nio/SocketChannelImpl.java b/luni/src/main/java/java/nio/SocketChannelImpl.java index ff2c157..233daf0 100644 --- a/luni/src/main/java/java/nio/SocketChannelImpl.java +++ b/luni/src/main/java/java/nio/SocketChannelImpl.java @@ -103,6 +103,15 @@ class SocketChannelImpl extends SocketChannel implements FileDescriptorChannel { } /* + * Constructor for use by Pipe.SinkChannel and Pipe.SourceChannel. + */ + public SocketChannelImpl(SelectorProvider selectorProvider, FileDescriptor existingFd) throws IOException { + super(selectorProvider); + status = SOCKET_STATUS_CONNECTED; + fd = existingFd; + } + + /* * Getting the internal Socket If we have not the socket, we create a new * one. */ diff --git a/luni/src/main/java/libcore/io/BlockGuardOs.java b/luni/src/main/java/libcore/io/BlockGuardOs.java index 61c9765..c61a3cf 100644 --- a/luni/src/main/java/libcore/io/BlockGuardOs.java +++ b/luni/src/main/java/libcore/io/BlockGuardOs.java @@ -181,6 +181,12 @@ public class BlockGuardOs extends ForwardingOs { return tagSocket(os.socket(domain, type, protocol)); } + @Override public void socketpair(int domain, int type, int protocol, FileDescriptor fd1, FileDescriptor fd2) throws ErrnoException { + os.socketpair(domain, type, protocol, fd1, fd2); + tagSocket(fd1); + tagSocket(fd2); + } + @Override public int write(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException { BlockGuard.getThreadPolicy().onWriteToDisk(); return os.write(fd, buffer); diff --git a/luni/src/main/java/libcore/io/ForwardingOs.java b/luni/src/main/java/libcore/io/ForwardingOs.java index 719c5f0..ee26d04 100644 --- a/luni/src/main/java/libcore/io/ForwardingOs.java +++ b/luni/src/main/java/libcore/io/ForwardingOs.java @@ -121,6 +121,7 @@ public class ForwardingOs implements Os { public void setuid(int uid) throws ErrnoException { os.setuid(uid); } public void shutdown(FileDescriptor fd, int how) throws ErrnoException { os.shutdown(fd, how); } public FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException { return os.socket(domain, type, protocol); } + public void socketpair(int domain, int type, int protocol, FileDescriptor fd1, FileDescriptor fd2) throws ErrnoException { os.socketpair(domain, type, protocol, fd1, fd2); } public StructStat stat(String path) throws ErrnoException { return os.stat(path); } public StructStatFs statfs(String path) throws ErrnoException { return os.statfs(path); } public String strerror(int errno) { return os.strerror(errno); } diff --git a/luni/src/main/java/libcore/io/Os.java b/luni/src/main/java/libcore/io/Os.java index 55588d8..1f42497 100644 --- a/luni/src/main/java/libcore/io/Os.java +++ b/luni/src/main/java/libcore/io/Os.java @@ -114,6 +114,7 @@ public interface Os { public void setuid(int uid) throws ErrnoException; public void shutdown(FileDescriptor fd, int how) throws ErrnoException; public FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException; + public void socketpair(int domain, int type, int protocol, FileDescriptor fd1, FileDescriptor fd2) throws ErrnoException; public StructStat stat(String path) throws ErrnoException; /* TODO: replace statfs with statvfs. */ public StructStatFs statfs(String path) throws ErrnoException; diff --git a/luni/src/main/java/libcore/io/Posix.java b/luni/src/main/java/libcore/io/Posix.java index ad01bcf..2fb187e 100644 --- a/luni/src/main/java/libcore/io/Posix.java +++ b/luni/src/main/java/libcore/io/Posix.java @@ -165,6 +165,7 @@ public final class Posix implements Os { public native void setuid(int uid) throws ErrnoException; public native void shutdown(FileDescriptor fd, int how) throws ErrnoException; public native FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException; + public native void socketpair(int domain, int type, int protocol, FileDescriptor fd1, FileDescriptor fd2) throws ErrnoException; public native StructStat stat(String path) throws ErrnoException; public native StructStatFs statfs(String path) throws ErrnoException; public native String strerror(int errno); diff --git a/luni/src/main/native/libcore_io_Posix.cpp b/luni/src/main/native/libcore_io_Posix.cpp index dd9b87f..acb3dc2 100644 --- a/luni/src/main/native/libcore_io_Posix.cpp +++ b/luni/src/main/native/libcore_io_Posix.cpp @@ -1168,6 +1168,15 @@ static jobject Posix_socket(JNIEnv* env, jobject, jint domain, jint type, jint p return fd != -1 ? jniCreateFileDescriptor(env, fd) : NULL; } +static void Posix_socketpair(JNIEnv* env, jobject, jint domain, jint type, jint protocol, jobject javaFd1, jobject javaFd2) { + int fds[2]; + int rc = throwIfMinusOne(env, "socketpair", TEMP_FAILURE_RETRY(socketpair(domain, type, protocol, fds))); + if (rc != -1) { + jniSetFileDescriptorOfFD(env, javaFd1, fds[0]); + jniSetFileDescriptorOfFD(env, javaFd2, fds[1]); + } +} + static jobject Posix_stat(JNIEnv* env, jobject, jstring javaPath) { return doStat(env, javaPath, false); } @@ -1341,6 +1350,7 @@ static JNINativeMethod gMethods[] = { NATIVE_METHOD(Posix, setuid, "(I)V"), NATIVE_METHOD(Posix, shutdown, "(Ljava/io/FileDescriptor;I)V"), NATIVE_METHOD(Posix, socket, "(III)Ljava/io/FileDescriptor;"), + NATIVE_METHOD(Posix, socketpair, "(IIILjava/io/FileDescriptor;Ljava/io/FileDescriptor;)V"), NATIVE_METHOD(Posix, stat, "(Ljava/lang/String;)Llibcore/io/StructStat;"), NATIVE_METHOD(Posix, statfs, "(Ljava/lang/String;)Llibcore/io/StructStatFs;"), NATIVE_METHOD(Posix, strerror, "(I)Ljava/lang/String;"), |