From 4e7dcb925c452ce07d45160e1173e0a8190b914b Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Wed, 21 Jun 2017 01:19:45 +0100 Subject: [PATCH] Thread detach hook for Java JNI on Android --- private/queue_private.h | 14 ++++++++++++++ src/queue.c | 17 +++++++++++++++++ src/swift/Queue.swift | 9 +++++++++ 3 files changed, 40 insertions(+) diff --git a/private/queue_private.h b/private/queue_private.h index 98c7f5e7b..b9356e25a 100644 --- a/private/queue_private.h +++ b/private/queue_private.h @@ -323,6 +323,20 @@ void dispatch_async_enforce_qos_class_f(dispatch_queue_t queue, void *_Nullable context, dispatch_function_t work); +#ifdef __ANDROID__ +/*! + * @function _dispatch_install_thread_detach_callback + * + * @param callback + * Function to be called before each worker thread exits to detach JVM. + * + * Hook to be able to detach threads from the Java JVM before they exit. + * If JNI has been used on a thread on Android it needs to have been + * "detached" before the thread exits or the application will crash. + */ +DISPATCH_EXPORT +void _dispatch_install_thread_detach_callback(dispatch_function_t cb); +#endif __END_DECLS diff --git a/src/queue.c b/src/queue.c index 4d506ef05..2406e7e7b 100644 --- a/src/queue.c +++ b/src/queue.c @@ -885,6 +885,18 @@ gettid(void) if ((f) && tsd->k) ((void(*)(void*))(f))(tsd->k); \ } while (0) +#ifdef __ANDROID__ +static void (*_dispatch_thread_detach_callback)(void); + +void +_dispatch_install_thread_detach_callback(dispatch_function_t cb) +{ + if (os_atomic_xchg(&_dispatch_thread_detach_callback, cb, relaxed)) { + DISPATCH_CLIENT_CRASH(0, "Installing a thread detach callback twice"); + } +} +#endif + void _libdispatch_tsd_cleanup(void *ctx) { @@ -909,6 +921,11 @@ _libdispatch_tsd_cleanup(void *ctx) _tsd_call_cleanup(dispatch_voucher_key, _voucher_thread_cleanup); _tsd_call_cleanup(dispatch_deferred_items_key, _dispatch_deferred_items_cleanup); +#ifdef __ANDROID__ + if (_dispatch_thread_detach_callback) { + _dispatch_thread_detach_callback(); + } +#endif tsd->tid = 0; } diff --git a/src/swift/Queue.swift b/src/swift/Queue.swift index 1808f9b06..b946a80f4 100644 --- a/src/swift/Queue.swift +++ b/src/swift/Queue.swift @@ -330,6 +330,15 @@ public extension DispatchQueue { let p = v.flatMap { Unmanaged.passRetained($0).toOpaque() } dispatch_queue_set_specific(self.__wrapped, k, p, _destructDispatchSpecificValue) } + + #if os(Android) + @_silgen_name("_dispatch_install_thread_detach_callback") + private static func _dispatch_install_thread_detach_callback(_ cb: @escaping @convention(c) () -> Void) + + public static func setThreadDetachCallback(_ cb: @escaping @convention(c) () -> Void) { + _dispatch_install_thread_detach_callback(cb) + } + #endif } private func _destructDispatchSpecificValue(ptr: UnsafeMutableRawPointer?) {