3 ms·
fork() Considered Harmful in macOS
- josephcsible 1mo ago[dead]
- dmitrygr 1mo agofork() was always very restricted in when it could be used and really dangerous even then. It was made for a world where process == thread, and since that ceased to be true it's been a large footgun. Use spawn if you need to launch a process, reconsider your life if your immediate post-fork() syscall is not exec()
- edelbitter 1mo agoBut what would the equivalent "do the expensive preparation 1 time, then re-use copy-on-write memory N times" pattern look like, after reconsidering my life?
- cestith 1mo agoThe manpage suggests if you need the child to be the same as the parent to exec a copy of the parent in the child right after forking.
- oasisaimlessly 1mo agoThis doesn't allow reusing initialization work via CoW mappings (like GP was asking about).
- cestith 1mo agoThis is an artifact of doing as the platform is documented to work. You can do what the man page says, or you can do the opposite. The whole article is about how forking on macOS is troublesome.
- zbentley 1mo agoIt looks like threads and a copy-on-write data structure or memory mapping.
- nasretdinov 1mo agoI believe what's being described in the article is the same reason why some shells like fish also use posix_spawn() on macOS instead of fork/exec. Not only is it much faster, but it's also effectively problem-free for multi-threaded applications
- cestith 1mo agoThe man page on macOS suggests that if you need the child to be a copy of the parent like you’d get after fork(), that you can fork() then exec() the same program in the child. That gives it enough independence to be safe. Using fork() without exec() was once a tried and true way to have a parent manage one or more children that just run a different branch of the code after the fork. It doesn’t work as well when you have a lot of async and a lot of fired signals right after forking, though. It gets worse if your signal handlers do more than, for example, assigning a value to a scalar variable and that’s honestly partially true of signal handlers no matter whether you’ve forked or not. That’s probably why Go blocks signals during that time after a fork(), for better or worse. So, TL;DR, if you need to run a child with the same code as the parent, exec() a copy like the manpage suggests especially on macOS. It’s a shame old Unix code that used this model won’t work as well as they used to across different Unix flavors. At least it's not much hassle to fix.
- dcrazy 1mo agoThe stubbornness of the Go standard library team knows no bounds.