Skip to content

Thread detach hook for Java JNI on Android #250

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 11 commits into from
12 changes: 12 additions & 0 deletions dispatch/queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -1346,6 +1346,18 @@ 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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for the second time this is NOT appropriate for an API header, this belongs to an internal one.
if the swift overlay is not built seeing the internal headers, then either try to fix that, or extern the prototype here again. it is an internal implementation detail between the overlay and libdispatch that should never be exposed anywhere.

this HAS to move to queue_internal.h, or maybe "private/private.h" this could be appropriate as well, and would likely be seen by the overlay.

Copy link
Contributor Author

@johnno1962 johnno1962 May 26, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There seems to be no way to expose the internal dispatch headers to the Swift side of things. There is a DispatchPrivate module but it won’t import during the build. So, I’ve used a @_silgen_name to pick up a setter function which isn’t ideal but at least it no longer affects the public api.

#endif
__END_DECLS

DISPATCH_ASSUME_NONNULL_END
Expand Down
8 changes: 8 additions & 0 deletions src/queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,10 @@ gettid(void)
if ((f) && tsd->k) ((void(*)(void*))(f))(tsd->k); \
} while (0)

#ifdef __ANDROID__
void (*_dispatch_thread_detach_callback)(void);
#endif

void
_libdispatch_tsd_cleanup(void *ctx)
{
Expand All @@ -885,6 +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);
#ifdef __ANDROID__
if (_dispatch_thread_detach_callback)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it was like this before, sorry to have missed it, please add brackets.

_dispatch_thread_detach_callback();
#endif
tsd->tid = 0;
}

Expand Down
11 changes: 11 additions & 0 deletions src/swift/Queue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 threadDetachCallback: @convention(c) () -> Void {
get {
return _dispatch_thread_detach_callback
}
set(newValue) {
_dispatch_thread_detach_callback = newValue
}
}
#endif
}

private func _destructDispatchSpecificValue(ptr: UnsafeMutableRawPointer?) {
Expand Down