Skip to content

Support WeakRef / FinalizationRegistry #1299

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

Open
dcodeIO opened this issue May 27, 2020 · 12 comments
Open

Support WeakRef / FinalizationRegistry #1299

dcodeIO opened this issue May 27, 2020 · 12 comments

Comments

@dcodeIO
Copy link
Member

dcodeIO commented May 27, 2020

An earlier issue suggested the implementation of a @destructor annotation, but it turned out that is is likely not feasible and we should instead aim for a more JS-like approach, i.e. along the lines of WeakRef and FinalizationRegistry since that's much safer. Also, since __finalize has been implemented recently, it should be possible now to roll custom solutions, or to investigate a JS-like approach further.

@WenheLI
Copy link

WenheLI commented Nov 15, 2020

Hi interested in this one! Any starting material for this issue?
Gentle ping @dcodeIO

@jtenner
Copy link
Contributor

jtenner commented May 18, 2021

I have a very specific use case for this in lunatic where a finalization registry might not be feasible either. I could ask the creator to implement rtrace host functions... But that might be a bad idea in general.

Any ideas?

@dcodeIO
Copy link
Member Author

dcodeIO commented May 18, 2021

Can you describe the concrete use case you have? That would help me to give you a better answer :)

@jtenner
Copy link
Contributor

jtenner commented May 18, 2021

When using lunatic, a socket can can be obtained like this:

let server = TCPServer.bind(ip, port);
let socket: TCPSocket;

while (socket = server.accept()) {
  // socket is now referenced once
  Process.spawn(socket, (theSocket: TCPSocket) => {
    // socket is now referenced twice, only now it's on another process
    socket.close();
    // now only once
  });
  // if we don't call socket.close() here, it will forever remain open, especially if it falls out of scope
}

As you can see, in languages like rust, we can automatically call socket.close() to effectively dereference it when it gets cleaned up by the memory manager.

Currently, it requires the user to make sure that they call socket.close() on every single process that touches a socket, which is not very ergonomic.

@jtenner
Copy link
Contributor

jtenner commented May 18, 2021

I also realize that the garbage collector may not run and the reference to the socket could still never be freed. It seems like there's no good solution here.

@dcodeIO
Copy link
Member Author

dcodeIO commented May 18, 2021

Yeah, hooking into the GC is most likely not a sufficient device for closing system resources, and may never be. One mechanism that comes to mind here, that's also present is JS, is to "transfer" a resource, so the current one becomes "detached". Perhaps something along these lines could help?

@jtenner
Copy link
Contributor

jtenner commented May 18, 2021

In the majority of cases, we actually want to reference a socket on multiple processes. In fact, without that feature, it becomes impossible to read and write to a socket asynchronously.

@dcodeIO
Copy link
Member Author

dcodeIO commented May 18, 2021

Would some sort of reference count on the socket work, so it is only actually closed once all threads have closed it?

@jtenner
Copy link
Contributor

jtenner commented May 18, 2021

That would be great, if memory was shared.

@dcodeIO
Copy link
Member Author

dcodeIO commented May 18, 2021

If you are using serialization, perhaps the RC can be incremented when a socket is serialized/deserialized? Only works of course if it can be guaranteed to map directly to active instances.

@jtenner
Copy link
Contributor

jtenner commented May 18, 2021

How can I do that when memory isn't shared? Every process is a separate web assembly module. Again, I actually think the right solution is to rename the function .close() and rename it to .deref() so that the user knows they must dereference the socket once it's done being used on that process.

@dcodeIO
Copy link
Member Author

dcodeIO commented May 18, 2021

Hmm, yeah, complicated. In this case, perhaps have an "owner" thread that is in unsafe charge of the socket, while in other threads the "close" is a noop. Not ideal, sadly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants