diff options
-rw-r--r-- | NativeCode.bp | 7 | ||||
-rw-r--r-- | luni/src/main/native/Android.bp | 1 | ||||
-rw-r--r-- | luni/src/main/native/AsynchronousCloseMonitor.cpp | 162 | ||||
-rw-r--r-- | luni/src/main/native/AsynchronousCloseMonitor.h | 79 | ||||
-rw-r--r-- | luni/src/main/native/libcore_io_AsynchronousCloseMonitor.cpp | 3 | ||||
-rw-r--r-- | luni/src/main/native/libcore_io_Linux.cpp | 2 | ||||
-rw-r--r-- | ojluni/src/main/native/linux_close.cpp | 3 |
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" { |