Callback into Java: when (how?) to detach a thread, which is not finished?

1,578 views
Skip to first unread message

Miha

unread,
Jun 30, 2011, 10:03:17 AM6/30/11
to android-ndk
Hi!

With regards to posts on thread [1], I'm not really sure when is it
safe to detach a thread?

I'm porting a big library which uses threads internally and I've
implemented callbacks in a way that they attach to java, call into
java, and then detach. The thread is still alive, though.

Now, I have no control when the thread will actaully finish, so I
can't call detach then. If I call detach in my callback handler, I'm
getting an error:
ERROR: detaching thread with interp frames.

I tried checking before attaching if I have access to JNIEnv (using
javaVM->GetEnv), and I don't. So I detach only if I previously attach,
but this is obviously not a good approach.

The question then is: when to detach? Or should I just leave it
attached, and it will detach when the application ends and threads
finish?

In the post[2] fadden writes that we must be careful to detach a
thread when it is about to exit (but I have no control over that). In
the same post, it is also not recommended to attach/detach on a
regular (frequent) basis -- for performance reasons.

Thanks,
Miha.

[1]: http://groups.google.com/group/android-ndk/browse_thread/thread/40f4dbc5d01bcf53

[2]:
http://groups.google.com/group/android-ndk/browse_thread/thread/f32dfc97f22aad0d/211d412108f4b2ab?lnk=gst&q=attaching#211d412108f4b2ab

fadden

unread,
Jun 30, 2011, 4:42:07 PM6/30/11
to android-ndk
On Jun 30, 7:03 am, Miha <miha.valen...@gmail.com> wrote:
> Now, I have no control when the thread will actaully finish, so I
> can't call detach then. If I call detach in my callback handler, I'm
> getting an error:
> ERROR: detaching thread with interp frames.

That means you're trying to detach a thread that is still executing
inside the VM. That would be bad.

> I tried checking before attaching if I have access to JNIEnv (using
> javaVM->GetEnv), and I don't. So I detach only if I previously attach,
> but this is obviously  not a good approach.

You can do this so long as you're attaching and detaching within the
span of a single function. If you do this across different callbacks
you're going to have races and other problems.

> The question then is: when to detach? Or should I just leave it
> attached, and it will detach when the application ends and threads
> finish?

As mentioned in [2], you can use a pthread_key_create destructor to
ensure that the detach happens when the thread is exiting. This only
works for Android 2.0+ ("Eclair" and later); before that it would
clash with the VM's internal enforcement mechanism.

Miha

unread,
Jun 30, 2011, 5:18:40 PM6/30/11
to android-ndk


On Jun 30, 10:42 pm, fadden <fad...@android.com> wrote:
> > ERROR: detaching thread with interp frames.
> That means you're trying to detach a thread that is still executing
> inside the VM.  That would be bad.
> > I tried checking before attaching if I have access to JNIEnv (using
> > javaVM->GetEnv), and I don't. So I detach only if I previously attach,
> > but this is obviously  not a good approach.
> You can do this so long as you're attaching and detaching within the
> span of a single function.  If you do this across different callbacks
> you're going to have races and other problems.

I was actually attaching and detaching inside of a single function and
I was getting the above error. The function (with logging statements
error checking omitted) is below. Any ideas why this does not work?

void callbackToJava(const int callbackId, const void* params)
{
bool shouldDetach = false;
JNIEnv *p_env;
jint rc = g_javaVM->GetEnv((void **)&p_env, JNI_VERSION_1_6);

// check if we should attach
if (rc != JNI_VERSION_1_6) {
shouldDetach = true;
rc = g_javaVM->AttachCurrentThread(&p_env, NULL);
}

if (g_callbackTarget != NULL) {
p_env->CallVoidMethod(g_callbackTarget, g_callbackMethod,
callbackId, (jobject)params);
}

if (shouldDetach) {
g_javaVM->DetachCurrentThread();
}
}

> As mentioned in [2], you can use a pthread_key_create destructor to
> ensure that the detach happens when the thread is exiting.  

As I'm targeting 2.3+, I'll try the pthread_key_create route.

Miha

unread,
Jun 30, 2011, 5:57:15 PM6/30/11
to android-ndk
One thing to note with pthread_key_create: I'm not sure when the the
destructor funcion is supposed to be called. It is not called at all
within the application. Or when I exit.

What is also strange is that every time I check if I need to attach
(by trying to GetEnv from javaVM), I do need to attach; I'm now
doubting that the checking I am doing is really what I should be
doing?

If I understood pthread_key_create functionality, destructor function
should be called if pointer is non-NULL; so I've set a pointer to some
bogus value:
void *ptr = (void*)0x0232023;
pthread_setspecific(key, ptr);

But the function does not get invoked.

Thanks,
Miha.

Luca Piccarreta

unread,
Jun 30, 2011, 9:42:09 PM6/30/11
to andro...@googlegroups.com
Hi Miha,

I lost a couple of hours on the very same problem (me lazy reading docs)

Description If the current thread is not attached to the given virtual machine instance, sets *penv to NULL, and returns JNI_EDETACHED. If the specified interface is not supported, sets *penv to NULL, and returns JNI_EVERSION. Otherwise, sets *env to the appropriate interface, and returns JNI_OK.

if (rc != JNI_VERSION_1_6)  {

should probably be:

if (rc != JNI_OK)  {

and JNI_EVERSION looks like an error state, not the actual version of the virtual machine.

Hope this solves your problem.

Luca.



--
You received this message because you are subscribed to the Google Groups "android-ndk" group.
To post to this group, send email to andro...@googlegroups.com.
To unsubscribe from this group, send email to android-ndk...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/android-ndk?hl=en.


Miha

unread,
Jul 1, 2011, 1:16:18 AM7/1/11
to android-ndk
Luca,

thank you! This is exactly what was wrong with my code.

Thanks,
Miha.

On Jul 1, 3:42 am, Luca Piccarreta <luca.piccarr...@gmail.com> wrote:
> Hi Miha,
>
> I lost a couple of hours on the very same problem (me lazy reading docs)
>
> if (rc != JNI_OK)  {
>

Luca Piccarreta

unread,
Jul 1, 2011, 4:03:10 AM7/1/11
to andro...@googlegroups.com
You too are a lazy docs reader... :)
Anyway, have a look at the suggestions from fad...@android.com, they look
simple and clever.


--

David Turner

unread,
Jul 1, 2011, 8:00:34 AM7/1/11
to andro...@googlegroups.com
On Thu, Jun 30, 2011 at 11:57 PM, Miha <miha.v...@gmail.com> wrote:
One thing to note with pthread_key_create: I'm not sure when the the
destructor funcion is supposed to be called. It is not called at all
within the application. Or when I exit.

For the record: it is called when any thread terminates (either by calling pthread_exit() or when its entry function returns).

Unless of course you called pthread_key_destroy() before that (in this case, it is your duty to ensure that each other thread has effectively destroyed the corresponding thread-local object).
 

Miha

unread,
Jul 1, 2011, 8:57:11 AM7/1/11
to android-ndk
Luca, David:

yes, I am a bit lazy reader; though, to my defense :)), the
documentation is scattered all over the place.

In my tests, the destructor function never got called. Then I changed
the attachment process (checking for JNI_OK instead of
JNI_VERSION_1_6) and now it gets called; It's a bit hard to test,
since I am not in control of those threads (they are created withing
the library I am using) -- and there is no documentation on when those
threads will finish, etc.

I'm still having some issue arround invocations back to Java, but it
looks like I am on the right track. The pthread_key_create route (now
that I got it working with help from you guys) seems like the best
option for me at the moment.

Thanks,
Miha.
Reply all
Reply to author
Forward
0 new messages