3 ms·
> The usual way is to ensure that after forking you only execute async-signal-safe code. Reading your comment I realised I misunderstood what the parent said.
by nh2 9y ago
> The usual way is to ensure that after forking you only execute async-signal-safe code.
Reading your comment I realised I misunderstood what the parent said. This misunderstanding is what made it a suprise for me.
Critically, I missed "... between the fork and the exec ..." and only considered the statement "the lock is still held by the new child process which deadlocks in malloc", assuming this was somehow the case even after the exec(), which would be a huge problem if even the exec()ed child wouldn't be allowed to malloc.
Of course on second thought this wrong assumption is nonsensical: When you exec(), you get a new process space, so any lock potentially thought up by libc or anything else, will be gone.
So all is fine:
For the purpose of starting another executable / implementing a popen(), one just must assure to not malloc (and as you say, in general write signal-handler-safe code) between fork and exec. This is feasible, and I suppose most programming languages do ensure that.
- ridiculous_fish 9y agoRight, however even this is harder than it looks. For example, what happens if exec fails? How do you print an error? Answer: very carefully - certainly not with printf!
- cryptonector 9y agoYou can write() to fildes 2, but I'd not recommend it. Instead what I'd recommend is that you have a pipe() for passing an error message (one byte will do) back to the parent, and then _exit().
- FooBarWidget 9y agoEven this is harder than it should be. What if the exec succeeds? The pipe is never closed. If you mark the pipe as O_CLOEXEC and rely on the parent treating EOF as success: what if the child crashes prematurely before exec? E.g. killed by sysadmin, or by OOM killer. What if a write() to the pipe fails?