ericwlange/AndroidJSCore

Multithreading and deadlock

bfortunato opened this issue · 21 comments

there are some deadlooks in the code

if i map a native async methhod with a js callback as parameter
native method call js callback
callback call another async native method
native method call js callback
callback call another async native method

deadlock is some cases

everything is executed in non ui-thread

I am at a loss for some of these deadlocking issues. You seem to be exercising the system in ways that others are not.

I have been a bit absent lately because I am working on another related project. I have ported the same Java API to a V8 backend (instead of JavaScriptCore). It is working nicely now and all of my AndroidJSCore tests are passing. I have not yet experienced any deadlocking as V8 allows me explicit control of mutexes. It brings other advantages too, specifically that I've also ported Node.js so you can run node processes as well.

At this point, I am not planning any more major overhauls of AndroidJSCore and instead will leave it as it is (with a possible 3.0.2 bug fix release, and/or integration of pull requests from contributors). Going forward all improvements will be on the new (currently unreleased) project.

Do you have a approximate time frame for the V8 project?

Give me till the weekend, Bruno. I'll send you a sneak preview.

Oh, sorry, I thought this was Bruno responding. Send me your email and I'll PM you.

Not sure how to PM you, you can find my email from my profile, thanks.

Hi,

I am encountering a similar issue, but have another data point in case it gives you a clue (or if you could point me in the right direction?)

  • Evaluate some JS
  • Call into JS from java with some parameters
  • repeat line above until lock.

Looks like context.sync(runnable) is where is gets stuck in JSValue.apply(), possibly waiting on the mutator lock.

Oddly, the number of calls that will succeed seems to depend on how big the parameters being passed into JS add up to cumulatively - My estimation would be that once 50 to 60Kb of parameter data has been passed in, the next call to JSValue.apply() will get stuck.

So for example if cb is a JSFunction that just does a console.log:

cb.call(mJSCore, "26Kb string here");
cb.call(mJSCore, "26Kb string here");    <--- Hangs

but also

cb.call(mJSCore, "7Kb string here");
cb.call(mJSCore, "7Kb string here");
cb.call(mJSCore, "7Kb string here");
cb.call(mJSCore, "7Kb string here");
cb.call(mJSCore, "7Kb string here");
cb.call(mJSCore, "7Kb string here");
cb.call(mJSCore, "7Kb string here");
cb.call(mJSCore, "7Kb string here");    <--- Hangs

Is some internal resource being exhausted, and indirectly causing a deadlock?

Any thoughts?

Thanks!

Perhaps also quite interestingly, it is not necessary to use call or apply

We just tried an experiment where we did:

mJSCore.property("object.attrib", "26Kb string here");
mJSCore.property("object.attrib", "26Kb string here");

(We also did the 7Kb version and a 14Kb version and it fails at about the 60Kb data transfer mark)

And this also hangs, suggesting it is something to do with the transfer of data into/out of the JS engine, and the use of context.sync() is the pinch-point, rather than a specific code path.

Hi Steve. Thanks for the info. Can you send me your email address? You can write me at eric (at) flicket (dot) tv. As mentioned above, I have a V8 version that uses the same (mostly) Java API. I want to understand if the problem persists there. That will help me know if the issue is on the Java or C++ side, considering the Java code is almost identical, but the C++ code differs dramatically.

I have not open sourced it yet, as it is not ready for general consumption, but can send you the library and javadocs for testing.

Same problems with big strings, of course.
There is some news here? Can you send me the lib too?

I am actually encountering the similar issue now. Everything seems to be fine until the threads count goes up to about 40. Afterwards, no threads can be executed and the app will hang to wait.
I checked the running threads, a lot of them are waiting. I guess it may caused by export objects. Such as I use some setTimeout in JavaScript and implement setTimeout natively. However, my setTimeout time is very short, the thread should be recycled soon.
Do you think it's because of your library or I use JSCore in a wrong way?

Btw, I have got your new V8 version but haven't got a chance to try it yet, will let you know.

Just tried on V8 version, the problem is now gone.
And I just verified that it's not because of the thread count.
Thanks

For those of you paying attention to this thread, please see my new project, LiquidCore (the new name for NodeDroid). I will be deprecating AndroidJSCore in favor of LiquidCore going forward.

Where I can find V8 version?

I also encountered this issue and switching to LiquidCore resolved the issue. Much appreciated!

Hey @ericwlange sorry to bother, but I'm incurring in the same, basically I the following scenario:

  • JS invokes a Java method (and I've checked that happens on a background)
  • The Java method needs to run something in the UI thread, therefore I use handler.postDelayed(runnable, 0);
  • The problem is that runnable is never executed since a deadlock is happening

I'm really confused about that, is there any workaround?
I think I'd be even fine to running every JS -> Java method on the main thread.

Appreciate your help :)

Hi @capezzbr,

AndroidJSCore is unsupported. Please upgrade to LiquidCore. The deadlock issues are under control there.

Eric

Thanks for the reply Eric, but unfortunately I have an entire app built on top of (an old version of) V8 and I wanted to move to another newer but also similar JS engine, like AndroidJSCore. The problem with https://github.com/LiquidPlayer/LiquidCore is that it looks like it's architectural very different from what I need. For instance it doesn't seem like I can pass a JS callback to native to be later invoked, true that that can be solved via a new event that I can publish from native, but I'd have to rewrite most of my app in order to support this new way of communicating between JS and native. I know that AndroidJSCore is now unsupported, but there is any future plan to keep improving its stability? Thanks

AndroidJSCore and LiquidCore are built using the same underlying Java code. LiquidCore just happens to have a lot more functionality, but you are not required to use it. You can use LiquidCore (almost) exactly the same as you are using AndroidJSCore. See here: https://github.com/LiquidPlayer/LiquidCore/wiki/LiquidCore-as-a-Native-Javascript-Engine

@ericwlange that's awesome, will definitely update to use LiquidCore and let you know if that fixes my issue 👍