Solution: the self-pipe trick. Maintain a pipe and select for readability on the pipe input. Inside the SIGCHLD handler, write a byte (non-blocking, just in case) to the pipe output. Done.
Of course, the Right Thing would be to have fork() return a file descriptor, not a process ID.
Subsequent appearances of the self-pipe trick: comp.unix.programmer, 1993.10.03, Chris Torek; dgclibcast6.c, 1997.09.01 (published 1998?), Richard Stevens; gtk-devel-list, 1998.11.22, Marius Vollmer; comp.os.linux.development.apps, 1998.12.20, Andi Kleen; linux-kernel, 1999.01.17, Andi Kleen; comp.unix.programmer, 1999.09.20, Mark Wooding; comp.unix.programmer, 1999.10.24, Mark Wooding; linux-kernel, 2000.06.27, Tommi Virtanen; comp.unix.programmer, 2000.07.01, Andrew Gierth; comp.unix.programmer, 2001.06.13, Chris Torek; perl-loop, 2001.07.11, Nick Ing-Simmons; linux-kernel, 2001.10.05, Lutz Vieweg.
You'd think that the self-pipe trick would be well known by now (2003.06). But the Linux SELECT_TUT documentation continues to claim that pselect(), which isn't supported by most UNIX kernels, is ``essential'' for programs that mix signals with select().