summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPete Bentley <prb@google.com>2019-02-06 10:58:56 +0000
committerPete Bentley <prb@google.com>2019-02-06 12:30:27 +0000
commitdfc8ce0458077409bfef8aaa157a04f103dc23a0 (patch)
tree328a107e3577d09e8a8947515af4f37acefeb125
parent83d51df23b460470320fa7187e1dcb85110de751 (diff)
Move AsynchronousCloseMonitor to libjavacore.
Final resting place tbd (see b/122881655) but this gets it out of libnativehelper. Bug: 122881655 Test: m && flashall Test: atest CtsLibcoreOkHttpTestCases:com.squareup.okhttp.CallTest Change-Id: I4354dd90f2ce5fa18734974efd1b6bad49ec0307
-rw-r--r--NativeCode.bp7
-rw-r--r--luni/src/main/native/Android.bp1
-rw-r--r--luni/src/main/native/AsynchronousCloseMonitor.cpp162
-rw-r--r--luni/src/main/native/AsynchronousCloseMonitor.h79
-rw-r--r--luni/src/main/native/libcore_io_AsynchronousCloseMonitor.cpp3
-rw-r--r--luni/src/main/native/libcore_io_Linux.cpp2
-rw-r--r--ojluni/src/main/native/linux_close.cpp3
7 files changed, 251 insertions, 6 deletions
diff --git a/NativeCode.bp b/NativeCode.bp
index f3b4217077..9e68b07069 100644
--- a/NativeCode.bp
+++ b/NativeCode.bp
@@ -86,6 +86,9 @@ cc_defaults {
"core_native_default_libs",
],
srcs: [":libopenjdk_native_srcs"],
+ include_dirs: [
+ "libcore/luni/src/main/native",
+ ],
cflags: [
// TODO(narayan): Prune down this list of exclusions once the underlying
// issues have been fixed. Most of these are small changes except for
@@ -100,9 +103,9 @@ cc_defaults {
shared_libs: [
"libcrypto",
"libicuuc",
- "libz",
-
+ "libjavacore",
"libnativehelper",
+ "libz",
],
static_libs: ["libfdlibm"],
diff --git a/luni/src/main/native/Android.bp b/luni/src/main/native/Android.bp
index e63fa42417..4e03c1fc22 100644
--- a/luni/src/main/native/Android.bp
+++ b/luni/src/main/native/Android.bp
@@ -1,6 +1,7 @@
filegroup {
name: "luni_native_srcs",
srcs: [
+ "AsynchronousCloseMonitor.cpp",
"ExecStrings.cpp",
"IcuUtilities.cpp",
"JniConstants.cpp",
diff --git a/luni/src/main/native/AsynchronousCloseMonitor.cpp b/luni/src/main/native/AsynchronousCloseMonitor.cpp
new file mode 100644
index 0000000000..7fea9367f5
--- /dev/null
+++ b/luni/src/main/native/AsynchronousCloseMonitor.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AsynchronousCloseMonitor"
+
+#include <log/log.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+
+#include <mutex>
+
+#include "AsynchronousCloseMonitor.h"
+
+namespace {
+
+class AsynchronousCloseMonitorImpl {
+public:
+ explicit AsynchronousCloseMonitorImpl(int fd);
+ ~AsynchronousCloseMonitorImpl();
+ bool wasSignaled() const;
+
+ static void init();
+
+ static void signalBlockedThreads(int fd);
+
+private:
+ AsynchronousCloseMonitorImpl(const AsynchronousCloseMonitorImpl&) = delete;
+ AsynchronousCloseMonitorImpl& operator=(const AsynchronousCloseMonitorImpl&) = delete;
+
+ AsynchronousCloseMonitorImpl* mPrev;
+ AsynchronousCloseMonitorImpl* mNext;
+ pthread_t mThread;
+ int mFd;
+ bool mSignaled;
+};
+
+/**
+ * We use an intrusive doubly-linked list to keep track of blocked threads.
+ * This gives us O(1) insertion and removal, and means we don't need to do any allocation.
+ * (The objects themselves are stack-allocated.)
+ * Waking potentially-blocked threads when a file descriptor is closed is O(n) in the total number
+ * of blocked threads (not the number of threads actually blocked on the file descriptor in
+ * question). For now at least, this seems like a good compromise for Android.
+ */
+static std::mutex blockedThreadListMutex;
+static AsynchronousCloseMonitorImpl* blockedThreadList = NULL;
+
+/**
+ * The specific signal chosen here is arbitrary, but bionic needs to know so that SIGRTMIN
+ * starts at a higher value.
+ */
+#if defined(__Fuchsia__)
+static const int BLOCKED_THREAD_SIGNAL = SIGRTMIN + 2;
+#else
+static const int BLOCKED_THREAD_SIGNAL = __SIGRTMIN + 2;
+#endif
+
+static void blockedThreadSignalHandler(int /*signal*/) {
+ // Do nothing. We only sent this signal for its side-effect of interrupting syscalls.
+}
+
+void AsynchronousCloseMonitorImpl::init() {
+ // Ensure that the signal we send interrupts system calls but doesn't kill threads.
+ // Using sigaction(2) lets us ensure that the SA_RESTART flag is not set.
+ // (The whole reason we're sending this signal is to unblock system calls!)
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = blockedThreadSignalHandler;
+ sa.sa_flags = 0;
+ int rc = sigaction(BLOCKED_THREAD_SIGNAL, &sa, NULL);
+ if (rc == -1) {
+ ALOGE("setting blocked thread signal handler failed: %s", strerror(errno));
+ }
+}
+
+void AsynchronousCloseMonitorImpl::signalBlockedThreads(int fd) {
+ std::lock_guard<std::mutex> lock(blockedThreadListMutex);
+ for (AsynchronousCloseMonitorImpl* it = blockedThreadList; it != NULL; it = it->mNext) {
+ if (it->mFd == fd) {
+ it->mSignaled = true;
+ pthread_kill(it->mThread, BLOCKED_THREAD_SIGNAL);
+ // Keep going, because there may be more than one thread...
+ }
+ }
+}
+
+bool AsynchronousCloseMonitorImpl::wasSignaled() const {
+ return mSignaled;
+}
+
+AsynchronousCloseMonitorImpl::AsynchronousCloseMonitorImpl(int fd) {
+ std::lock_guard<std::mutex> lock(blockedThreadListMutex);
+ // Who are we, and what are we waiting for?
+ mThread = pthread_self();
+ mFd = fd;
+ mSignaled = false;
+ // Insert ourselves at the head of the intrusive doubly-linked list...
+ mPrev = NULL;
+ mNext = blockedThreadList;
+ if (mNext != NULL) {
+ mNext->mPrev = this;
+ }
+ blockedThreadList = this;
+}
+
+AsynchronousCloseMonitorImpl::~AsynchronousCloseMonitorImpl() {
+ std::lock_guard<std::mutex> lock(blockedThreadListMutex);
+ // Unlink ourselves from the intrusive doubly-linked list...
+ if (mNext != NULL) {
+ mNext->mPrev = mPrev;
+ }
+ if (mPrev == NULL) {
+ blockedThreadList = mNext;
+ } else {
+ mPrev->mNext = mNext;
+ }
+}
+
+} // namespace
+
+//
+// C ABI and API boundary
+//
+
+extern "C" {
+void async_close_monitor_static_init() {
+ AsynchronousCloseMonitorImpl::init();
+}
+
+void async_close_monitor_signal_blocked_threads(int fd) {
+ AsynchronousCloseMonitorImpl::signalBlockedThreads(fd);
+}
+
+void* async_close_monitor_create(int fd) {
+ return new AsynchronousCloseMonitorImpl(fd);
+}
+
+void async_close_monitor_destroy(void* instance) {
+ auto monitor = reinterpret_cast<AsynchronousCloseMonitorImpl*>(instance);
+ delete monitor;
+}
+
+int async_close_monitor_was_signalled(const void* instance) {
+ auto monitor = reinterpret_cast<const AsynchronousCloseMonitorImpl*>(instance);
+ return monitor->wasSignaled() ? 1 : 0;
+}
+}
diff --git a/luni/src/main/native/AsynchronousCloseMonitor.h b/luni/src/main/native/AsynchronousCloseMonitor.h
new file mode 100644
index 0000000000..5bccf3d701
--- /dev/null
+++ b/luni/src/main/native/AsynchronousCloseMonitor.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ASYNCHRONOUS_CLOSE_MONITOR_H_included
+#define ASYNCHRONOUS_CLOSE_MONITOR_H_included
+
+#include <pthread.h>
+
+// Public API for library function.
+extern "C" {
+void async_close_monitor_destroy(void* instance);
+void async_close_monitor_static_init();
+void async_close_monitor_signal_blocked_threads(int fd);
+int async_close_monitor_was_signalled(const void* instance);
+void* async_close_monitor_create(int fd);
+}
+
+/**
+ * AsynchronousCloseMonitor helps implement Java's asynchronous close semantics.
+ *
+ * AsynchronousCloseMonitor::init must be called before anything else.
+ *
+ * Every blocking I/O operation must be surrounded by an AsynchronousCloseMonitor
+ * instance. For example:
+ *
+ * {
+ * AsynchronousCloseMonitor monitor(fd);
+ * byteCount = ::read(fd, buf, sizeof(buf));
+ * }
+ *
+ * To interrupt all threads currently blocked on file descriptor 'fd', call signalBlockedThreads:
+ *
+ * AsynchronousCloseMonitor::signalBlockedThreads(fd);
+ *
+ * To test to see if the interruption was due to the signalBlockedThreads call:
+ *
+ * monitor.wasSignaled();
+ */
+class AsynchronousCloseMonitor {
+public:
+ explicit AsynchronousCloseMonitor(int fd) {
+ instance_ = async_close_monitor_create(fd);
+ }
+ ~AsynchronousCloseMonitor() {
+ async_close_monitor_destroy(instance_);
+ }
+ bool wasSignaled() const {
+ return async_close_monitor_was_signalled(instance_) != 0;
+ }
+
+ static void init() {
+ async_close_monitor_static_init();
+ }
+
+ static void signalBlockedThreads(int fd) {
+ async_close_monitor_signal_blocked_threads(fd);
+ }
+
+private:
+ AsynchronousCloseMonitor(const AsynchronousCloseMonitor&) = delete;
+ AsynchronousCloseMonitor& operator=(const AsynchronousCloseMonitor&) = delete;
+
+ void* instance_;
+};
+
+#endif // ASYNCHRONOUS_CLOSE_MONITOR_H_included
diff --git a/luni/src/main/native/libcore_io_AsynchronousCloseMonitor.cpp b/luni/src/main/native/libcore_io_AsynchronousCloseMonitor.cpp
index d9119c8ded..55803b8d8d 100644
--- a/luni/src/main/native/libcore_io_AsynchronousCloseMonitor.cpp
+++ b/luni/src/main/native/libcore_io_AsynchronousCloseMonitor.cpp
@@ -16,10 +16,11 @@
#define LOG_TAG "AsynchronousCloseMonitor"
-#include <nativehelper/AsynchronousCloseMonitor.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/jni_macros.h>
+#include "AsynchronousCloseMonitor.h"
+
static void AsynchronousCloseMonitor_signalBlockedThreads(JNIEnv* env, jclass, jobject javaFd) {
int fd = jniGetFDFromFileDescriptor(env, javaFd);
AsynchronousCloseMonitor::signalBlockedThreads(fd);
diff --git a/luni/src/main/native/libcore_io_Linux.cpp b/luni/src/main/native/libcore_io_Linux.cpp
index 55de1bd7f9..5d621de238 100644
--- a/luni/src/main/native/libcore_io_Linux.cpp
+++ b/luni/src/main/native/libcore_io_Linux.cpp
@@ -58,7 +58,6 @@
#include <android-base/macros.h>
#include <android-base/strings.h>
#include <log/log.h>
-#include <nativehelper/AsynchronousCloseMonitor.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedBytes.h>
#include <nativehelper/ScopedLocalRef.h>
@@ -67,6 +66,7 @@
#include <nativehelper/jni_macros.h>
#include <nativehelper/toStringArray.h>
+#include "AsynchronousCloseMonitor.h"
#include "ExecStrings.h"
#include "JniConstants.h"
#include "JniException.h"
diff --git a/ojluni/src/main/native/linux_close.cpp b/ojluni/src/main/native/linux_close.cpp
index 5b4829289b..baef240c6b 100644
--- a/ojluni/src/main/native/linux_close.cpp
+++ b/ojluni/src/main/native/linux_close.cpp
@@ -47,8 +47,7 @@
#include <poll.h>
#endif
-
-#include <nativehelper/AsynchronousCloseMonitor.h>
+#include <AsynchronousCloseMonitor.h>
extern "C" {