-
Notifications
You must be signed in to change notification settings - Fork 284
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
Ability to call Javascript methods from Rust threads #197
Comments
I've made a bit of progress with this but am stuck! @dherman perhaps you can help me. I've managed to invoke a Rust function using Am struggling both with Rust basics and the idiomatic Neon way this should work. Any advice/pointers gratefully received. I can't even tell if I'm close or not!! My working Rust project (so far) is here: My working C++ project (which does invoke the js callback) is here: The C++ project shows the basic approach to converting a
and (in callback):
|
IIRC this is where I left off when attempting async callbacks with Neon. We need a way to persist the callback so that Rust doesn't drop it when the call goes out of scope. I spoke with @dherman about this (a while back) and we (at the time) thought it was best to not introduce the idea of |
I agree... that's what I meant by finding an idiomatic Neon way of doing it. The Neon developer (hopefully) shouldn't concern themselves with local and persistent. I wondered if it would be possible to make Call (or it's arguments) Send or Sync. Then they could be passed across the thread boundary. I don't know if this even makes sense as a suggestion though, or how hard it would be! |
@jugglingcats I think you have some of the right ideas, but I don't have the complete picture in my head so I can't spell out exactly what needs to be done. I can give you a few thoughts, though: Unfortunately, it's not safe for another Rust thread to call JS on its same thread -- we can't allow that, because a) the GC isn't multithreaded and the callback closes over data from the main thread, and b) having multiple threads work on arbitrary shared data violates JS's run-to-completion semantics. (Does your C code do that, btw? It's possible I'm missing something but I'd expect that generally to crash or cause strange unspecified behavior.) The only safe thing to do, AFAIK, would be to let the Rust background thread add events onto the main thread's queue, to be dispatched on the main thread. Similarly, it's not safe to let Call or other data structures like that implement Send or Sync, because again they are pointing to JS data from the main thread. What I believe we want to do, at least at a hand-wavy level, is bridge between JS's concept of dynamic transferring (and maybe also structured clone) and Rust's ownership. So for example, it should be possible to transfer a typed array to a background Rust thread and then let Rust transfer it back to the callback when it's done doing the work. If we set the types up so that it's a dynamic error to try to send non-transferrable data to the background thread, then we'll be guaranteed to be thread-safe. Another way of thinking about this is that this is kind of like web workers and postMessage, except that we can probably make the API nicer. I'd be happy to collaborate with you on this when I have time, btw. Right now I'm trying to get the web site presentable because we're planning on doing some blog posts about using Neon with Electron and how Wire has recently put Neon into production, and I want people to have a good landing experience. After that I have a couple of hacking projects on various parts of Neon that I want to do, but having more powerful ways to do background computation in Rust is a high-priority use case. |
Hi @dherman, agree mostly with your analysis. The postMessage analogy is not quite correct though IMO, because with postMessage you are limited strictly to transferring data, whereas within a node addon, you can pass a Javascript callback (function) around. You cannot execute the callback in another thread, but you can pass it around and provided you marshall onto the main node (libuv) thread you can call it later. The key to passing the callback (and any other node data) around is converting from There are two methods of marshalling onto the main node thread that I'm aware of, with slightly different semantics:
This is convenient for ad-hoc long running native tasks because node does the thread pool management.
The C++ example I posted shows the mechanism for uv_async_send, but doesn't actually do any threading. But the structure is correct regarding Now for my bit of hand waving... It seems to me that Rust should have a way to mutate data when sending it across threads. I don't understand the mechanics of this, but something Sync or Send should be able to say "hey, I see I'm being transferred across thread boundary, I need to do xxxxx". If this were possible, you could encapsulate the switch from Appreciate you are busy with other activity. This isn't super-urgent for us: we don't need this feature right away. But am interested to see how it progresses -- I think it could work very sweetly. |
Should be possible to contain the response data in a movable object with the callback and just hand it to libuv to execute in the |
Can you elaborate a little? It is the javascript function handle that needs to be kept around, to be invoked later during the async send native callback (on main thread) |
@jugglingcats Are you on the slack today? I'd be happy to chat -- I've been looking into this issue lately. |
Any updates? @jugglingcats @dherman continuous calls into a javascript function from Rust is a feature I looking forward to for a long time :) |
As #375 merged, what is the roadmap ahead for full implementation? |
@Acanguven The feature is currently not stabalized. Currently there is a limitation to the API that may require a breaking change. Specifically, it is not possible to handle Javascript exceptions in the scheduled Rust callback. One proposal is the implementation of a Lastly, the schedule API passes a Thanks! |
I have an example I've worked through today based on the test cases for the |
@tom-haines can you point me towards your repo? |
This has been implemented with |
As discussed on Slack: https://rust-bindings.slack.com/archives/neon/p1489508576491688.
The basic idea is that a Rust addon can create a continuous background thread that notifies Javascript when things happen (event style).
Psuedo Javascript:
Psuedo Rust:
If this was achievable it would be a lot nicer than the C equivalent, an example of which is here: https://gist.github.com/matzoe/11082417.
I imagine there would need to be some kind of wrapper around the call, so maybe not completely transparent as shown above.
The text was updated successfully, but these errors were encountered: