diff options
author | Elliott Hughes <enh@google.com> | 2014-12-15 16:14:56 -0800 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2014-12-17 10:16:23 -0800 |
commit | fa542091e45db699a937c5ac0191194405107827 (patch) | |
tree | a09af98504fb8287e825fa96778d7df481eb4caa /luni/src | |
parent | ae5e913146e8840b1e692f92299473268f90f415 (diff) | |
download | libcore-fa542091e45db699a937c5ac0191194405107827.zip libcore-fa542091e45db699a937c5ac0191194405107827.tar.gz libcore-fa542091e45db699a937c5ac0191194405107827.tar.bz2 |
Fix poll to never return EINTR.
Bug: 18759467
Change-Id: Ia5b97a55318b5990ad6b80d15641223aa4fb06f5
Diffstat (limited to 'luni/src')
-rw-r--r-- | luni/src/main/java/android/system/Os.java | 4 | ||||
-rw-r--r-- | luni/src/main/java/java/nio/SelectorImpl.java | 5 | ||||
-rw-r--r-- | luni/src/main/java/libcore/io/IoBridge.java | 6 | ||||
-rw-r--r-- | luni/src/main/native/libcore_io_Posix.cpp | 64 | ||||
-rw-r--r-- | luni/src/test/java/libcore/java/nio/channels/SelectorTest.java | 21 |
5 files changed, 56 insertions, 44 deletions
diff --git a/luni/src/main/java/android/system/Os.java b/luni/src/main/java/android/system/Os.java index 7f73a85..2626685 100644 --- a/luni/src/main/java/android/system/Os.java +++ b/luni/src/main/java/android/system/Os.java @@ -308,6 +308,10 @@ public final class Os { /** * See <a href="http://man7.org/linux/man-pages/man2/poll.2.html">poll(2)</a>. + * + * <p>Note that in Lollipop this could throw an {@code ErrnoException} with {@code EINTR}. + * In later releases, the implementation will automatically just restart the system call with + * an appropriately reduced timeout. */ public static int poll(StructPollfd[] fds, int timeoutMs) throws ErrnoException { return Libcore.os.poll(fds, timeoutMs); } diff --git a/luni/src/main/java/java/nio/SelectorImpl.java b/luni/src/main/java/java/nio/SelectorImpl.java index 5e2a2b1..c73ba22 100644 --- a/luni/src/main/java/java/nio/SelectorImpl.java +++ b/luni/src/main/java/java/nio/SelectorImpl.java @@ -38,7 +38,6 @@ import libcore.io.IoBridge; import libcore.io.IoUtils; import libcore.io.Libcore; -import static android.system.OsConstants.EINTR; import static android.system.OsConstants.POLLERR; import static android.system.OsConstants.POLLHUP; import static android.system.OsConstants.POLLIN; @@ -183,9 +182,7 @@ final class SelectorImpl extends AbstractSelector { try { rc = Libcore.os.poll(pollFds.array(), (int) timeout); } catch (ErrnoException errnoException) { - if (errnoException.errno != EINTR) { - throw errnoException.rethrowAsIOException(); - } + throw errnoException.rethrowAsIOException(); } } finally { if (isBlocking) { diff --git a/luni/src/main/java/libcore/io/IoBridge.java b/luni/src/main/java/libcore/io/IoBridge.java index acc8d4f..fcb30dd 100644 --- a/luni/src/main/java/libcore/io/IoBridge.java +++ b/luni/src/main/java/libcore/io/IoBridge.java @@ -225,11 +225,7 @@ public final class IoBridge { if (!fd.valid()) { throw new SocketException("Socket closed"); } - if (errnoException.errno == EINTR) { - return false; // Punt and ask the caller to try again. - } else { - cause = errnoException; - } + cause = errnoException; } String detail = connectDetail(inetAddress, port, timeoutMs, cause); if (cause.errno == ETIMEDOUT) { diff --git a/luni/src/main/native/libcore_io_Posix.cpp b/luni/src/main/native/libcore_io_Posix.cpp index 57ff794..c585fc5 100644 --- a/luni/src/main/native/libcore_io_Posix.cpp +++ b/luni/src/main/native/libcore_io_Posix.cpp @@ -551,7 +551,7 @@ static void Posix_execve(JNIEnv* env, jobject, jstring javaFilename, jobjectArra ExecStrings argv(env, javaArgv); ExecStrings envp(env, javaEnvp); - execve(path.c_str(), argv.get(), envp.get()); + TEMP_FAILURE_RETRY(execve(path.c_str(), argv.get(), envp.get())); throwErrnoException(env, "execve"); } @@ -563,7 +563,7 @@ static void Posix_execv(JNIEnv* env, jobject, jstring javaFilename, jobjectArray } ExecStrings argv(env, javaArgv); - execv(path.c_str(), argv.get()); + TEMP_FAILURE_RETRY(execv(path.c_str(), argv.get())); throwErrnoException(env, "execv"); } @@ -724,15 +724,15 @@ static jobjectArray Posix_android_getaddrinfo(JNIEnv* env, jobject, jstring java } static jint Posix_getegid(JNIEnv*, jobject) { - return getegid(); + return TEMP_FAILURE_RETRY(getegid()); } static jint Posix_geteuid(JNIEnv*, jobject) { - return geteuid(); + return TEMP_FAILURE_RETRY(geteuid()); } static jint Posix_getgid(JNIEnv*, jobject) { - return getgid(); + return TEMP_FAILURE_RETRY(getgid()); } static jstring Posix_getenv(JNIEnv* env, jobject, jstring javaName) { @@ -764,11 +764,11 @@ static jobject Posix_getpeername(JNIEnv* env, jobject, jobject javaFd) { } static jint Posix_getpid(JNIEnv*, jobject) { - return getpid(); + return TEMP_FAILURE_RETRY(getpid()); } static jint Posix_getppid(JNIEnv*, jobject) { - return getppid(); + return TEMP_FAILURE_RETRY(getppid()); } static jobject Posix_getpwnam(JNIEnv* env, jobject, jstring javaName) { @@ -867,14 +867,14 @@ static jint Posix_gettid(JNIEnv* env __unused, jobject) { } return static_cast<jint>(owner); #elif defined(__BIONIC__) - return gettid(); + return TEMP_FAILURE_RETRY(gettid()); #else return syscall(__NR_gettid); #endif } static jint Posix_getuid(JNIEnv*, jobject) { - return getuid(); + return TEMP_FAILURE_RETRY(getuid()); } static jstring Posix_if_indextoname(JNIEnv* env, jobject, jint index) { @@ -1088,7 +1088,40 @@ static jint Posix_poll(JNIEnv* env, jobject, jobjectArray javaStructs, jint time for (size_t i = 0; i < count; ++i) { monitors.push_back(new AsynchronousCloseMonitor(fds[i].fd)); } - int rc = poll(fds.get(), count, timeoutMs); + + int rc; + while (true) { + timespec before; + clock_gettime(CLOCK_MONOTONIC, &before); + + rc = poll(fds.get(), count, timeoutMs); + if (rc >= 0 || errno != EINTR) { + break; + } + + // We got EINTR. Work out how much of the original timeout is still left. + if (timeoutMs > 0) { + timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + timespec diff; + diff.tv_sec = now.tv_sec - before.tv_sec; + diff.tv_nsec = now.tv_nsec - before.tv_nsec; + if (diff.tv_nsec < 0) { + --diff.tv_sec; + diff.tv_nsec += 1000000000; + } + + jint diffMs = diff.tv_sec * 1000 + diff.tv_nsec / 1000000; + if (diffMs >= timeoutMs) { + rc = 0; // We have less than 1ms left anyway, so just time out. + break; + } + + timeoutMs -= diffMs; + } + } + for (size_t i = 0; i < monitors.size(); ++i) { delete monitors[i]; } @@ -1115,7 +1148,8 @@ static void Posix_posix_fallocate(JNIEnv* env, jobject, jobject javaFd __unused, "fallocate doesn't exist on a Mac"); #else int fd = jniGetFDFromFileDescriptor(env, javaFd); - errno = TEMP_FAILURE_RETRY(posix_fallocate64(fd, offset, length)); + while ((errno = posix_fallocate64(fd, offset, length)) == EINTR) { + } if (errno != 0) { throwErrnoException(env, "posix_fallocate"); } @@ -1128,9 +1162,11 @@ static jint Posix_prctl(JNIEnv* env, jobject, jint option __unused, jlong arg2 _ jniThrowException(env, "java/lang/UnsupportedOperationException", "prctl doesn't exist on a Mac"); return 0; #else - int result = prctl(static_cast<int>(option), - static_cast<unsigned long>(arg2), static_cast<unsigned long>(arg3), - static_cast<unsigned long>(arg4), static_cast<unsigned long>(arg5)); + int result = TEMP_FAILURE_RETRY(prctl(static_cast<int>(option), + static_cast<unsigned long>(arg2), + static_cast<unsigned long>(arg3), + static_cast<unsigned long>(arg4), + static_cast<unsigned long>(arg5))); return throwIfMinusOne(env, "prctl", result); #endif } diff --git a/luni/src/test/java/libcore/java/nio/channels/SelectorTest.java b/luni/src/test/java/libcore/java/nio/channels/SelectorTest.java index 9789197..41b434d 100644 --- a/luni/src/test/java/libcore/java/nio/channels/SelectorTest.java +++ b/luni/src/test/java/libcore/java/nio/channels/SelectorTest.java @@ -15,7 +15,6 @@ */ package libcore.java.nio.channels; -import android.system.OsConstants; import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerSocket; @@ -28,7 +27,6 @@ import java.nio.channels.SocketChannel; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import junit.framework.TestCase; -import libcore.io.Libcore; import tests.net.StuckServer; public class SelectorTest extends TestCase { @@ -71,25 +69,6 @@ public class SelectorTest extends TestCase { } } - // http://b/6453247 - // This test won't work on the host until/unless we start using libcorkscrew there. - // The runtime itself blocks SIGQUIT, so that doesn't cause poll(2) to EINTR directly. - // The EINTR is caused by the way libcorkscrew works. - public void testEINTR() throws Exception { - Selector selector = Selector.open(); - new Thread(new Runnable() { - @Override public void run() { - try { - Thread.sleep(2000); - Libcore.os.kill(Libcore.os.getpid(), OsConstants.SIGQUIT); - } catch (Exception ex) { - fail(); - } - } - }).start(); - assertEquals(0, selector.select()); - } - // http://code.google.com/p/android/issues/detail?id=15388 public void testInterrupted() throws IOException { Selector selector = Selector.open(); |