Plan 9 sysexec clears pending notes (unlike posix which leaves pending
signals active across exec). So if fork+exec is followed immediately
by postnote("kill"), there is a window in sysexec between the last sleep
and the clearing of up->nnote where the note from the parent can be lost.
This also triggers another bug: exec clears up->nnote but does not clear
up->notepending, and therefore the first system call in the child
process which calls sleep() will be wrongly terminated with Eintr.
The parent process can detect when the child's exec has succeeded,
by opening a close-on-exec file before the fork, and waiting for
it to be closed before sending a note. (The Go language runtime,
for example, does this.) To eliminate the exec-postnote race in
this case, this patch moves the close-on-exec code to a later point
in the sysexec function, after pending notes have been cleared.
The race could be eliminated more simply by not clearing up->nnote
on exec, but that would change the semantics of exec and possibly
disturb some existing programs.
|