3 ms·
There are basically 2 unrelated uses of fork(): * In single-threaded programs (potentially without calling exec). This was widely used to get parallelism withi
by o11c 2y ago
There are basically 2 unrelated uses of fork():
* In single-threaded programs (potentially without calling exec). This was widely used to get parallelism within a single program prior to 1995 or so, and is still a valid approach (except on OS X, which forbids single-threaded programs). In this case `pthread_atfork` is a reasonable thing to use, and the child process is not limited to async-signal-safe functions.
* In (potentially-multi-threaded) programs calling exec. In this case, `pthread_atfork` is not meaningful (there's a recent `_Fork` that avoids it entirely), and the child is limited to async-signal-safe functions - basically, you should do all the setup beforehand, then after `fork` just call various syscalls. `posix_spawn` and `vfork` may replace this, but both are bug-prone.
- saagarjha 2y ago> except on OS X, which forbids single-threaded programs …uh, what?
- o11c 2y agoIn recent years, Apple's libc will aggressively create threads to perform background tasks. There is no way to prevent this. Thus, calling fork() on OS X means you can only use async-signal-safe functions, unlike other platforms where abstinence is a choice.
- plorkyeran 2y agoThere’s a lot of system libraries on macOS that’ll spawn threads, but I’ve definitely never seen libc do so.
- olliej 2y agoNo, you can fork, what you can’t do is “fork and then try to keep running after the fork”. That’s never really been a supported model on Darwin, and in recent years with more threading occurring it fails faster than it did in the past. On Darwin there is very little you can safely do in the child after fork(), essentially the only thing guaranteed to work at that point is exec() and a few other basic operations. Again, this has always been the case for fork under Darwin, the only difference is that you are more likely to fail sooner now than 20 years ago. This is also why all documentation says to use posix_spawn: fork +exec is necessarily slower, and can’t really do anything that posix spawn doesn’t.
- o11c 2y ago> can’t really do anything that posix spawn doesn’t. This is blatantly untrue. Probably the most common example is `chdir`, but there's a whole list in signal-safety(7). Using a shim is always a possibility but that's annoying.
- amelius 2y agoI sounds to me that while fork() was perhaps initially a simple idea, it has now (with multithreading etc) become a monstrosity that is better replaced by a number of syscalls that are less general and have more intent behind them. Perhaps fork() will go away naturally when other options turn out to be faster or people start porting stuff to Darwin and other OSes where fork() is not a good idea anyway.