summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2012-09-28 15:53:29 -0700
committerBrian Carlstrom <bdc@google.com>2012-10-03 17:15:29 -0700
commitb2e6be1cc1d375ca2fc28ee1fdfc10c0adc2554d (patch)
tree6e906dd3bafe851b3cf050e1744aa771e8ad181b
parent77b2088858b199e60002bfb2acb7a883c6aba82a (diff)
downloadlibcore-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.java46
-rw-r--r--luni/src/main/java/java/nio/SelectorProviderImpl.java2
-rw-r--r--luni/src/main/java/java/nio/SocketChannelImpl.java9
-rw-r--r--luni/src/main/java/libcore/io/BlockGuardOs.java6
-rw-r--r--luni/src/main/java/libcore/io/ForwardingOs.java1
-rw-r--r--luni/src/main/java/libcore/io/Os.java1
-rw-r--r--luni/src/main/java/libcore/io/Posix.java1
-rw-r--r--luni/src/main/native/libcore_io_Posix.cpp10
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;"),