NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/49017: vfork does not suspend all threads



The following reply was made to PR kern/49017; it has been noted by GNATS.

From: Robert Elz <kre%munnari.OZ.AU@localhost>
To: gnats-bugs%NetBSD.org@localhost
Cc: 
Subject: Re: kern/49017: vfork does not suspend all threads
Date: Thu, 06 Apr 2017 10:08:40 +0700

 It appears to me as if the discussion on this has largely divided
 along traditional lines - those who (fundamentally) believe that
 vfork() is an evil hack, and should be removed (ideally) but in the
 meantime restricted in all ways possible to limit its use, so that
 hopefully it can go away some day not too far away - and those who
 believe vfork() is a valuable tool, which should be exploited in
 all ways possible, and enhanced where practical to make it even more
 useful.
 
 As long as that division persists, there will never be consensus on
 anything related to vfork().
 
 While I certainly agree that the man page description of vfork() as
 "stopping the parent process" is irrelevant to the current issue, as
 others have said, that was written in an age when there were no threads,
 not even as a possibility on the horizon, and was just never changed again.
 Whatever relationship might have existed between vfork() and threads seems
 to have simply been ignored (because vfork() proponents, and thread
 proponents, seem to largely be disjoint sets, or were.)
 
 Before going further, I think it useful to actually understand vfork() a
 little better - first it is (kind of) badly named, as in most respects it
 is not a fork() type function at all, it is rather a kind of setjmp()/longjmp()
 with some peculiar semantics - and a new proc struct (and hence new pid,
 and anything that affects only the proc struct, like setuid() being magic).
 
 That is, in reality, what happens is that the "parent" process both stalls,
 and continues running (just like with setjmp()) until the terminating
 condition occurs (the longjmp() equiv - _exit() or exec()) - and (here
 I disagree with Nico) the "child" process after a vfork() can do just about
 anything that would be safe between a setjmp() and longjmp(), unless the
 operation does something which would require a proc struct alteration which
 is also reflected in user space (so brk() is bad).
 
 There's no need to restrict vfork() children to async signal safe operations
 (the process limiting itself that way certainly won't hurt it, but it is
 not required) - it can do anything that the parent can do that affects only
 its internal (userland) state, or which affects purely the proc struct
 state in the kernel (so it can close files, or change the "close on exec"
 state, but not other file status flags).
 
 Of course, the parent needs to expect all of this - it needs to co-operate
 with the child, just as is required with a setjmp()/longjmp(), and understand
 just what the "child" might have done with the memory image after it gets
 a chance to observe.
 
 What all this means to a threaded process, is that overall I'm of the opinion
 that only the parent thread should block (just as if the parent thread used
 a setjmp()) and whatever sync with other threads should be just the same for
 the child of the vfork() as it would have been for the thread had it not done
 a vfork(), with the sole exception that the child cannot use, or rely upon,
 anything that uses kernel process private state (and hence cannot access, or
 change, anything which would be protected by such a mechanism).   In process
 type spin locks, would be safe, sys call activated sleeping locks would not be.
 
 kre
 
 ps: unrelated here, but the one facility missing from vfork() that would make
 it more useful, would be a "complete the fork" sys call, which would turn the
 vfork() into a fork() (dup the addr space) and be a third "wakeup the parent"
 operation.
 


Home | Main Index | Thread Index | Old Index