> There is some prep for ugly contingencies(pthread_atfork) but it usually just works.
Actually, that's not true. Perhaps it's theoretically possible, in some cases, to make your threaded code work with fork with the appropriate pthread_atfork() handlers, but in general, it's a total mess. Thread A has a lock, thread B calls fork(), thread B tries to acquire the lock. The lock is held, but thread A is not running in the child. That much should be obvious.
The usual fix is to write a pthread_atfork() handler for every lock in your program. Before forking, it locks all of your mutexes. After forking, in both the child and parent, it unlocks them. You can see the holes in this. One simple hole is that fork() is async signal safe but pthread_mutex_lock() is not, but most people won't fork() in a signal anyway. The big problem is that you now need to make all of your locks recursive and figure out, globally, what order to lock them in. This means registering your atfork() handlers in exactly the right order, something which is more difficult than it sounds. Another problem is the performance implications of acquiring all the locks in your program.
Namespaces + threads are fine, the only problem here is namespaces + M:N threads + no method for pinning a green thread to an OS thread, like forkOS in Haskell.
> Namespaces + threads are fine, the only problem here is namespaces + M:N threads + no method for pinning a green thread to an OS thread, like forkOS in Haskell.
Not quite. unshare(CLONE_NEWUSER) and setns(fd, CLONE_NEWNS) require your process to be single-threaded. So precise control over threading is needed.
On paper, all code between a fork and exec (in a multithreaded process) must be async-signal safe as well. I'm not sure if this is also true for the callbacks with pthread_atfork (I've personally never used it), but it's something to keep in mind.
There’s a defect report somewhere about this exact topic—there’s no requirement that pthread_atfork handlers are async-signal-safe, but fork is marked as async-signal-safe. The question is whether the documentation should be fixed, whether atfork handlers should just not run if fork is called in a signal handler, etc. IMO if someone’s forking in a signal handler in a multithreaded program nothing good is going to happen anyway.
*...it's a total mess...theoretically it's possible....speculation on standard behavior based
on platform behavior...namespace(x)<-threads->chosen implementation detail...functional language reference...
-- Translation: Design is broken
> If a multi-threaded process calls fork() ... the child process may only execute async-signal-safe operations until such time as one of the exec functions is called.
I don't know about "design is broken". I personally think the fork()/exec() model is a clumsy way to create a new process, but that's a matter of taste.
Actually, that's not true. Perhaps it's theoretically possible, in some cases, to make your threaded code work with fork with the appropriate pthread_atfork() handlers, but in general, it's a total mess. Thread A has a lock, thread B calls fork(), thread B tries to acquire the lock. The lock is held, but thread A is not running in the child. That much should be obvious.
The usual fix is to write a pthread_atfork() handler for every lock in your program. Before forking, it locks all of your mutexes. After forking, in both the child and parent, it unlocks them. You can see the holes in this. One simple hole is that fork() is async signal safe but pthread_mutex_lock() is not, but most people won't fork() in a signal anyway. The big problem is that you now need to make all of your locks recursive and figure out, globally, what order to lock them in. This means registering your atfork() handlers in exactly the right order, something which is more difficult than it sounds. Another problem is the performance implications of acquiring all the locks in your program.
Namespaces + threads are fine, the only problem here is namespaces + M:N threads + no method for pinning a green thread to an OS thread, like forkOS in Haskell.