2 ms·
You could use a file instead, but `pipe` is the most portable way to not leave clutter on the system if something goes wrong. If you need traffic in both direct
by o11c 2y ago
You could use a file instead, but `pipe` is the most portable way to not leave clutter on the system if something goes wrong. If you need traffic in both directions, `socketpair` is useful (and I think portable across platforms that support networking as we know it).
Less-portable or less-reliable alternatives include `memfd`, a deleted-but-still-open tempfile, etc.
To avoid problems with failure after `exec`, it is very important to fork+exec the server first just to see if it actually starts. If you don't need the PID to remain the same you can actually just use that instance without the other fork or another exec (this still keeps the same PGID). Note that "failure after `exec`" can be fairly sharply divided into "error in C runtime (usually, library compatibility)" and "error in something `main` calls", which require very different approaches.
---
Aside: I've had catastrophic failures using the "save after fork" approach (mentioned later in the article) when the child process crashed before the save completed, and the parent just kept trying to have the child save (I also managed to completely crash GDB while investigating this). It is very important for the parent to commit suicide if the child can't do its job, to minimize the amount of lost data.
The other thing I would recommend to anyone working with this kind of thing: use systemd and commit all the way; it will make your life 1000% easier than trying to reimplement it badly yourself.
- skissane 2y ago> `socketpair` is useful (and I think portable across platforms that support networking as we know it) Windows is a notable platform not supporting socketpair. Some languages offer socketpair on Windows, e.g. Python, but they are implementing it themselves using TCP loopback connections. Somewhat irrelevant to this discussion given Windows lacks exec (starting a new executable requires a new process which gets a new PID), and in practice lacks fork too (the low-level NT API has undocumented support for forking, but most of the higher-level APIs get confused by it and break when you use it, making it unusable by the vast majority of applications)
- skissane 2y ago> Somewhat irrelevant to this discussion given Windows lacks exec (starting a new executable requires a new process which gets a new PID), Well, you can do exec() on Windows if you implement it yourself in user space, see e.g. https://github.com/polycone/pe-loader https://github.com/polycone/pe-loader (a bit of a dated project, 32-bit only, but the I believe the same principles apply to 64-bit) Cygwin uses a hack – exec() creates a new Windows process, but every Cygwin process has two PIDs, a Windows PID and a Cygwin PID, so exec() changes the Windows PID but keeps the Cygwin PID the same – so it looks like an exec to Cygwin processes, but just like an ordinary spawn to non-Cygwin processes Less insane approach: if you put most of your code in a DLL, you can unload the DLL and then load a new version of it