-
Notifications
You must be signed in to change notification settings - Fork 30.7k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Passing fd between threads causes VM to crash, or EBADF #30507
Comments
Ah. After further research, I found the following note in the worker threads documentation :
Was the NodeJS team planning on implementing this feature similar to how you can send a handle using subprocess.send ? Is there a way around it using C++ or an experimental feature? |
Fwiw, the reason for the crashes would most likely be that two different event loops are trying to manage the same socket and, amongst other things, close the file descriptor when they are done with it, unaware of the other event loop also handling the fd.
It’s on my long-term TODO list, but it gets tricky when thinking about things like Windows support. At this point the best way to do this is probably to try and re-use the code we use for child processes, and use something like libuv/libuv#1498 to create a fake internal IPC channel of some sorts to pass handles within a single process.
Not that I am aware of. |
That would make a lot of sense. Since the fd is part of two different event loops, once it has to be destroyed, it's being closed and gc'ed twice. I wonder if there would be a way to create a weak fd like you would create a weak reference? Let's say you create a At the moment, once a file descriptor is associated with, let's say, a Something like this :
Mind if I play around with it and open a PR, or is it something you would like to avoid? |
@rykdesjardins Where would you get that If you want to go the easy way and are mostly concerned about lifetime management, I guess you could work on a PR that makes libuv close its handle without closing the fd itself; basically, removing the internal state that libuv has built around it, and then allowing another thread to open that fd? libuv/libuv#390 went a bit into that direction, and I think it would be the ideal way to tackle this, but … I always got kind of stumped when thinking about how one might support something like this on Windows. 🙁 I don’t know the API there well enough, but you’d still need to pass the If this ends up making its way into Node.js core, it should definitely come with Windows support, and it should handle situations gracefully in which the receiving thread goes away before it actually receives the fd/handle. |
From forks to threads
I was working on moving from forks to Worker Threads and was experimenting with passing file descriptors between threads. Forks work great with passing file descriptors around due to the extended IPC, making it possible to share open ports.
Sharing file descriptors
Using Worker Threads, this becomes impossible, For that reason, I had to create a master thread handling connection events, and pass those connections to worker threads through
postMessage
. Since the whole object cannot be passed through message, I thought the lightest and fastest way to do this would be to post the fd as a message, and have the worker thread create a newSocket
using the fd.It works great until it does not. It is really unpredictable, but always seems to crash at some point.
Repro steps
Here is the smallest portion of code I could come up with to reproduce the issue. Those are two files : master.js and worker.js.
Full test HERE.
After an unpredictable while, I get either one of those two errors :
or
This is something I used to do in C++ : have a master thread handle incoming connections, and pass the
fd
integer to whatever thread is available. Maybe I'm misunderstanding how Nodejs handles file descriptors in the background?The full example I wrote had a worker pool and sometimes was able to handle over 5000 requests before crashing. The crashes are random.
If it can help, here is the
stress.js
file I used to conduct the tests.Let me know if you need more info, or if I simply misunderstand how to use this feature.
Notes
This also happens with file streams, and sockets on top of HTTP.
The text was updated successfully, but these errors were encountered: