From c3c0befd4d4a8de708fdfd7ed8021ec8ec6b9189 Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Tue, 23 May 2017 00:58:37 +0100 Subject: [PATCH 01/10] Thread detach hook for Java JNI on Android --- dispatch/queue.h | 10 ++++++++++ src/queue.c | 4 ++++ src/swift/Queue.swift | 11 +++++++++++ 3 files changed, 25 insertions(+) diff --git a/dispatch/queue.h b/dispatch/queue.h index b1dd8e547..10d20b168 100644 --- a/dispatch/queue.h +++ b/dispatch/queue.h @@ -1346,6 +1346,16 @@ dispatch_assert_queue_not(dispatch_queue_t queue) #define dispatch_assert_queue_not_debug(q) dispatch_assert_queue_not(q) #endif +/*! + * @handler dispatch_thread_detach_handler + * + * Hook to be able to detach threads before they exit from the Java JVM. + * 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_thread_detach_handler)(); + __END_DECLS DISPATCH_ASSUME_NONNULL_END diff --git a/src/queue.c b/src/queue.c index 42b51f3eb..e1a73c608 100644 --- a/src/queue.c +++ b/src/queue.c @@ -861,6 +861,8 @@ gettid(void) if ((f) && tsd->k) ((void(*)(void*))(f))(tsd->k); \ } while (0) +void (*dispatch_thread_detach_handler)(); + void _libdispatch_tsd_cleanup(void *ctx) { @@ -885,6 +887,8 @@ _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); + if (dispatch_thread_detach_handler) + dispatch_thread_detach_handler(); tsd->tid = 0; } diff --git a/src/swift/Queue.swift b/src/swift/Queue.swift index b7628c9cf..5c12dcbc8 100644 --- a/src/swift/Queue.swift +++ b/src/swift/Queue.swift @@ -330,6 +330,17 @@ public extension DispatchQueue { let p = Unmanaged.passRetained(v).toOpaque() dispatch_queue_set_specific(self.__wrapped, k, p, _destructDispatchSpecificValue) } + + #if os(Android) + public static var threadCleanupCallback: @convention(c) () -> Void { + get { + return dispatch_thread_detach_handler + } + set(newValue) { + dispatch_thread_detach_handler = newValue + } + } + #endif } private func _destructDispatchSpecificValue(ptr: UnsafeMutableRawPointer?) { From 96bc6b645bfbd789bd6ef46e5cb332dfa26792eb Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Tue, 23 May 2017 07:55:46 +0100 Subject: [PATCH 02/10] Thread detach hook for Java JNI on Android II --- dispatch/queue.h | 7 ++++--- src/queue.c | 10 +++++++--- src/swift/Queue.swift | 4 ++-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/dispatch/queue.h b/dispatch/queue.h index 10d20b168..0c6a4cbc9 100644 --- a/dispatch/queue.h +++ b/dispatch/queue.h @@ -1346,6 +1346,8 @@ dispatch_assert_queue_not(dispatch_queue_t queue) #define dispatch_assert_queue_not_debug(q) dispatch_assert_queue_not(q) #endif + +#ifdef __ANDROID__ /*! * @handler dispatch_thread_detach_handler * @@ -1354,10 +1356,9 @@ dispatch_assert_queue_not(dispatch_queue_t queue) * "detached" before the thread exits or the application will crash. */ DISPATCH_EXPORT -void (*dispatch_thread_detach_handler)(); - +void (*_dispatch_thread_detach_handler)(void); +#endif __END_DECLS DISPATCH_ASSUME_NONNULL_END - #endif diff --git a/src/queue.c b/src/queue.c index e1a73c608..bd707164a 100644 --- a/src/queue.c +++ b/src/queue.c @@ -861,7 +861,9 @@ gettid(void) if ((f) && tsd->k) ((void(*)(void*))(f))(tsd->k); \ } while (0) -void (*dispatch_thread_detach_handler)(); +#ifdef __ANDROID__ +void (*_dispatch_thread_detach_handler)(void); +#endif void _libdispatch_tsd_cleanup(void *ctx) @@ -887,8 +889,10 @@ _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); - if (dispatch_thread_detach_handler) - dispatch_thread_detach_handler(); +#ifdef __ANDROID__ + if (_dispatch_thread_detach_handler) + _dispatch_thread_detach_handler(); +#endif tsd->tid = 0; } diff --git a/src/swift/Queue.swift b/src/swift/Queue.swift index 5c12dcbc8..606b95a33 100644 --- a/src/swift/Queue.swift +++ b/src/swift/Queue.swift @@ -334,10 +334,10 @@ public extension DispatchQueue { #if os(Android) public static var threadCleanupCallback: @convention(c) () -> Void { get { - return dispatch_thread_detach_handler + return _dispatch_thread_detach_handler } set(newValue) { - dispatch_thread_detach_handler = newValue + _dispatch_thread_detach_handler = newValue } } #endif From b6003edd7e53bdb76509b5208fc4a7158f382fbc Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Tue, 23 May 2017 08:06:16 +0100 Subject: [PATCH 03/10] Thread detach hook for Java JNI on Android III --- dispatch/queue.h | 1 + 1 file changed, 1 insertion(+) diff --git a/dispatch/queue.h b/dispatch/queue.h index 0c6a4cbc9..c5eda2e75 100644 --- a/dispatch/queue.h +++ b/dispatch/queue.h @@ -1361,4 +1361,5 @@ void (*_dispatch_thread_detach_handler)(void); __END_DECLS DISPATCH_ASSUME_NONNULL_END + #endif From 8bf5bcf312adf4b814ae8f614ff57a9d2b5c0891 Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Thu, 25 May 2017 02:46:48 +0100 Subject: [PATCH 04/10] Renamed for consistency --- dispatch/queue.h | 4 ++-- src/queue.c | 6 +++--- src/swift/Queue.swift | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dispatch/queue.h b/dispatch/queue.h index c5eda2e75..5b7f5debf 100644 --- a/dispatch/queue.h +++ b/dispatch/queue.h @@ -1349,14 +1349,14 @@ dispatch_assert_queue_not(dispatch_queue_t queue) #ifdef __ANDROID__ /*! - * @handler dispatch_thread_detach_handler + * @handler dispatch_thread_detach_callback * * Hook to be able to detach threads before they exit from the Java JVM. * 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_thread_detach_handler)(void); +void (*_dispatch_thread_detach_callback)(void); #endif __END_DECLS diff --git a/src/queue.c b/src/queue.c index bd707164a..36817c02e 100644 --- a/src/queue.c +++ b/src/queue.c @@ -862,7 +862,7 @@ gettid(void) } while (0) #ifdef __ANDROID__ -void (*_dispatch_thread_detach_handler)(void); +void (*_dispatch_thread_detach_callback)(void); #endif void @@ -890,8 +890,8 @@ _libdispatch_tsd_cleanup(void *ctx) _tsd_call_cleanup(dispatch_deferred_items_key, _dispatch_deferred_items_cleanup); #ifdef __ANDROID__ - if (_dispatch_thread_detach_handler) - _dispatch_thread_detach_handler(); + 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 606b95a33..41b545f43 100644 --- a/src/swift/Queue.swift +++ b/src/swift/Queue.swift @@ -332,12 +332,12 @@ public extension DispatchQueue { } #if os(Android) - public static var threadCleanupCallback: @convention(c) () -> Void { + public static var threadDetachCallback: @convention(c) () -> Void { get { - return _dispatch_thread_detach_handler + return _dispatch_thread_detach_callback } set(newValue) { - _dispatch_thread_detach_handler = newValue + _dispatch_thread_detach_callback = newValue } } #endif From bd5461809e63a6e7a16a9dac6e05db2672854d1a Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Fri, 26 May 2017 22:25:48 +0100 Subject: [PATCH 05/10] Revert public API change --- dispatch/queue.h | 12 ------------ src/queue.c | 11 ++++++++--- src/queue_internal.h | 11 +++++++++++ src/swift/Queue.swift | 9 ++++++--- 4 files changed, 25 insertions(+), 18 deletions(-) diff --git a/dispatch/queue.h b/dispatch/queue.h index 5b7f5debf..b1dd8e547 100644 --- a/dispatch/queue.h +++ b/dispatch/queue.h @@ -1346,18 +1346,6 @@ dispatch_assert_queue_not(dispatch_queue_t queue) #define dispatch_assert_queue_not_debug(q) dispatch_assert_queue_not(q) #endif - -#ifdef __ANDROID__ -/*! - * @handler dispatch_thread_detach_callback - * - * Hook to be able to detach threads before they exit from the Java JVM. - * 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_thread_detach_callback)(void); -#endif __END_DECLS DISPATCH_ASSUME_NONNULL_END diff --git a/src/queue.c b/src/queue.c index 36817c02e..e2137cffc 100644 --- a/src/queue.c +++ b/src/queue.c @@ -862,7 +862,11 @@ gettid(void) } while (0) #ifdef __ANDROID__ -void (*_dispatch_thread_detach_callback)(void); +static void (*_dispatch_thread_detach_callback)(void); + +void _dispatch_set_detach_callback( void (*callback)(void) ) { + _dispatch_thread_detach_callback = callback; +} #endif void @@ -890,8 +894,9 @@ _libdispatch_tsd_cleanup(void *ctx) _tsd_call_cleanup(dispatch_deferred_items_key, _dispatch_deferred_items_cleanup); #ifdef __ANDROID__ - if (_dispatch_thread_detach_callback) - _dispatch_thread_detach_callback(); + if (_dispatch_thread_detach_callback) { + _dispatch_thread_detach_callback(); + } #endif tsd->tid = 0; } diff --git a/src/queue_internal.h b/src/queue_internal.h index 91a31864a..46eca1003 100644 --- a/src/queue_internal.h +++ b/src/queue_internal.h @@ -1039,4 +1039,15 @@ _dispatch_queue_is_exclusively_owned_by_current_thread_4IOHID( #endif // __APPLE__ +#ifdef __ANDROID__ +/*! + * @handler dispatch_thread_detach_callback + * + * 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_set_detach_callback( void (*callback)(void) ); +#endif #endif diff --git a/src/swift/Queue.swift b/src/swift/Queue.swift index 41b545f43..cef136367 100644 --- a/src/swift/Queue.swift +++ b/src/swift/Queue.swift @@ -332,12 +332,15 @@ public extension DispatchQueue { } #if os(Android) - public static var threadDetachCallback: @convention(c) () -> Void { + @_silgen_name("_dispatch_set_detach_callback") + private static func _dispatch_set_detach_callback( _ callback: (@convention(c) () -> Void)? ) + + public static var threadDetachCallback: (@convention(c) () -> Void)? { get { - return _dispatch_thread_detach_callback + return nil } set(newValue) { - _dispatch_thread_detach_callback = newValue + _dispatch_set_detach_callback( newValue ) } } #endif From 4be52da9a67ca26b8b096ecb6e17868d8620425e Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Sat, 27 May 2017 07:28:14 +0100 Subject: [PATCH 06/10] Move to queue_private.h --- private/queue_private.h | 11 +++++++++++ src/queue_internal.h | 11 ----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/private/queue_private.h b/private/queue_private.h index 14d64772d..6d0cc1042 100644 --- a/private/queue_private.h +++ b/private/queue_private.h @@ -322,6 +322,17 @@ void dispatch_async_enforce_qos_class_f(dispatch_queue_t queue, void *_Nullable context, dispatch_function_t work); +#ifdef __ANDROID__ +/*! + * @handler _dispatch_thread_detach_callback + * + * 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_set_detach_callback( void (*callback)(void) ); +#endif __END_DECLS diff --git a/src/queue_internal.h b/src/queue_internal.h index 46eca1003..91a31864a 100644 --- a/src/queue_internal.h +++ b/src/queue_internal.h @@ -1039,15 +1039,4 @@ _dispatch_queue_is_exclusively_owned_by_current_thread_4IOHID( #endif // __APPLE__ -#ifdef __ANDROID__ -/*! - * @handler dispatch_thread_detach_callback - * - * 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_set_detach_callback( void (*callback)(void) ); -#endif #endif From 10ea8cf1a6b6a63ca24707d06a71b3d760a8503a Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Sat, 27 May 2017 13:46:34 +0100 Subject: [PATCH 07/10] Implemented getter --- private/queue_private.h | 2 ++ src/queue.c | 3 +++ src/swift/Queue.swift | 5 ++++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/private/queue_private.h b/private/queue_private.h index 6d0cc1042..cd19041a2 100644 --- a/private/queue_private.h +++ b/private/queue_private.h @@ -332,6 +332,8 @@ dispatch_async_enforce_qos_class_f(dispatch_queue_t queue, */ DISPATCH_EXPORT void _dispatch_set_detach_callback( void (*callback)(void) ); +DISPATCH_EXPORT +void (*_dispatch_get_detach_callback(void))(void); #endif __END_DECLS diff --git a/src/queue.c b/src/queue.c index e2137cffc..31462d52f 100644 --- a/src/queue.c +++ b/src/queue.c @@ -867,6 +867,9 @@ static void (*_dispatch_thread_detach_callback)(void); void _dispatch_set_detach_callback( void (*callback)(void) ) { _dispatch_thread_detach_callback = callback; } +void (*_dispatch_get_detach_callback(void))(void) { + return _dispatch_thread_detach_callback; +} #endif void diff --git a/src/swift/Queue.swift b/src/swift/Queue.swift index cef136367..886720342 100644 --- a/src/swift/Queue.swift +++ b/src/swift/Queue.swift @@ -334,10 +334,13 @@ public extension DispatchQueue { #if os(Android) @_silgen_name("_dispatch_set_detach_callback") private static func _dispatch_set_detach_callback( _ callback: (@convention(c) () -> Void)? ) + @_silgen_name("_dispatch_get_detach_callback") + private static func _dispatch_get_detach_callback() -> (@convention(c) () -> Void)? public static var threadDetachCallback: (@convention(c) () -> Void)? { get { - return nil + return _dispatch_get_detach_callback() + } set(newValue) { _dispatch_set_detach_callback( newValue ) From 12163ba46b01b8dd82d76bbb1ee7b14928995c91 Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Sat, 27 May 2017 14:46:07 +0100 Subject: [PATCH 08/10] Single entry point --- private/queue_private.h | 6 ++---- src/queue.c | 8 +++----- src/swift/Queue.swift | 11 ++++------- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/private/queue_private.h b/private/queue_private.h index cd19041a2..409f45a48 100644 --- a/private/queue_private.h +++ b/private/queue_private.h @@ -324,16 +324,14 @@ dispatch_async_enforce_qos_class_f(dispatch_queue_t queue, #ifdef __ANDROID__ /*! - * @handler _dispatch_thread_detach_callback + * @handler _dispatch_thread_detach_callback_ptr * * 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_set_detach_callback( void (*callback)(void) ); -DISPATCH_EXPORT -void (*_dispatch_get_detach_callback(void))(void); +void *(*_dispatch_thread_detach_callback_ptr(void))(void); #endif __END_DECLS diff --git a/src/queue.c b/src/queue.c index 31462d52f..66b8a2e55 100644 --- a/src/queue.c +++ b/src/queue.c @@ -864,11 +864,9 @@ gettid(void) #ifdef __ANDROID__ static void (*_dispatch_thread_detach_callback)(void); -void _dispatch_set_detach_callback( void (*callback)(void) ) { - _dispatch_thread_detach_callback = callback; -} -void (*_dispatch_get_detach_callback(void))(void) { - return _dispatch_thread_detach_callback; +void +*(*_dispatch_thread_detach_callback_ptr(void))(void) { + return &_dispatch_thread_detach_callback; } #endif diff --git a/src/swift/Queue.swift b/src/swift/Queue.swift index 886720342..d3162b693 100644 --- a/src/swift/Queue.swift +++ b/src/swift/Queue.swift @@ -332,18 +332,15 @@ public extension DispatchQueue { } #if os(Android) - @_silgen_name("_dispatch_set_detach_callback") - private static func _dispatch_set_detach_callback( _ callback: (@convention(c) () -> Void)? ) - @_silgen_name("_dispatch_get_detach_callback") - private static func _dispatch_get_detach_callback() -> (@convention(c) () -> Void)? + @_silgen_name("_dispatch_thread_detach_callback_ptr") + private static func _dispatch_thread_detach_callback_ptr() -> UnsafeMutablePointer<(@convention(c) () -> Void)?> public static var threadDetachCallback: (@convention(c) () -> Void)? { get { - return _dispatch_get_detach_callback() - + return _dispatch_thread_detach_callback_ptr().pointee } set(newValue) { - _dispatch_set_detach_callback( newValue ) + _dispatch_thread_detach_callback_ptr().pointee = newValue } } #endif From 0a5722698ace909e8eb7c721d08dbed34a421d2f Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Sun, 28 May 2017 10:01:49 +0100 Subject: [PATCH 09/10] Setter only --- private/queue_private.h | 7 +++++-- src/queue.c | 7 +++++-- src/swift/Queue.swift | 13 ++++--------- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/private/queue_private.h b/private/queue_private.h index 409f45a48..796ce50d4 100644 --- a/private/queue_private.h +++ b/private/queue_private.h @@ -324,14 +324,17 @@ dispatch_async_enforce_qos_class_f(dispatch_queue_t queue, #ifdef __ANDROID__ /*! - * @handler _dispatch_thread_detach_callback_ptr + * @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_thread_detach_callback_ptr(void))(void); +void _dispatch_install_thread_detach_callback(dispatch_function_t cb); #endif __END_DECLS diff --git a/src/queue.c b/src/queue.c index 66b8a2e55..005d5330f 100644 --- a/src/queue.c +++ b/src/queue.c @@ -865,8 +865,11 @@ gettid(void) static void (*_dispatch_thread_detach_callback)(void); void -*(*_dispatch_thread_detach_callback_ptr(void))(void) { - return &_dispatch_thread_detach_callback; +_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 diff --git a/src/swift/Queue.swift b/src/swift/Queue.swift index d3162b693..29e2bf777 100644 --- a/src/swift/Queue.swift +++ b/src/swift/Queue.swift @@ -332,16 +332,11 @@ public extension DispatchQueue { } #if os(Android) - @_silgen_name("_dispatch_thread_detach_callback_ptr") - private static func _dispatch_thread_detach_callback_ptr() -> UnsafeMutablePointer<(@convention(c) () -> Void)?> + @_silgen_name("_dispatch_install_thread_detach_callback") + private static func _dispatch_install_thread_detach_callback(_ cb: @escaping @convention(c) () -> Void) - public static var threadDetachCallback: (@convention(c) () -> Void)? { - get { - return _dispatch_thread_detach_callback_ptr().pointee - } - set(newValue) { - _dispatch_thread_detach_callback_ptr().pointee = newValue - } + public static func setThreadDetachCallback(_ cb: @escaping @convention(c) () -> Void) { + _dispatch_install_thread_detach_callback(cb) } #endif } From 39eddf2308c0d0e2459eb9b9be19bbb9c4abed71 Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Tue, 23 May 2017 00:58:37 +0100 Subject: [PATCH 10/10] Thread detach hook for Java JNI on Android Thread detach hook for Java JNI on Android II Thread detach hook for Java JNI on Android III Renamed for consistency Revert public API change Move to queue_private.h Implemented getter Single entry point Setter only --- 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 14d64772d..796ce50d4 100644 --- a/private/queue_private.h +++ b/private/queue_private.h @@ -322,6 +322,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 42b51f3eb..005d5330f 100644 --- a/src/queue.c +++ b/src/queue.c @@ -861,6 +861,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) { @@ -885,6 +897,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 b7628c9cf..29e2bf777 100644 --- a/src/swift/Queue.swift +++ b/src/swift/Queue.swift @@ -330,6 +330,15 @@ public extension DispatchQueue { let p = Unmanaged.passRetained(v).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?) {