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