ccl
ccl copied to clipboard
Fix Unix subprocess signalling: Signal external process process-group
Hello all,
Context
Signalling in Unix sometimes requires signalling not only a process with a given pid, but also all the processes under a given process-group.
Example: In contexts where an external process might spawn child processes, like a shell spawning subprocesses, killing the shell process means that the childen processes get reassigned to the init process with PID 1 and keep running even after the shell and even the Lisp implementation that launched said processes dies, which in some situations creates very undesirable resource leakages.
In Unix, fixing this requires sending a signal to the process group instead of the process with a given process id.
Signalling the process group is therefore important and can be done by calling kill with (- pid) instead of pid.
We are trying to make ASDF's uiop:launch-program and uiop:terminate-process more reliable on all Lisp implementations under Unix (see https://gitlab.common-lisp.net/asdf/asdf/-/issues/92).
Unix specifies that the kill system call can either signal the process with pid, or its whole process group -pid.
We can implement this by calling the kill system utility (hack), or by adding the capability in ccl of signalling not only the process but its process group. This is of course can be useful not only to kill processes, but also to communicate with the process children.
Proposal
One way to do this is to follow sbcl's sb-ext:process-kill, which supports an optional argument whom which can take either :pid or :process-group values. If the latter is passed, then the kill system call is performed with -pid instead of pid (they actually use killpg instead, but that's only a convenience syscall that does the same thing).
We propose adding an optional parameter target with the same semantics of sbcl's whom to ccl's signal-external-process which currently has this form:
(defun signal-external-process (proc signal &key (error-if-exited t))
"Send the specified signal to the specified external process. (Typically,
it would only be useful to call this function if the EXTERNAL-PROCESS was
created with :WAIT NIL.) Return T if successful; NIL if the process wasn't
created successfully, and signal an error otherwise."
(require-type proc 'external-process)
(let* ((pid (external-process-pid proc)))
(when pid
(let ((error (int-errno-call (#_kill pid signal))))
(or (eql error 0)
(unless (and (eql error (- #$ESRCH))
(not error-if-exited))
(%errno-disp error)))))))
Is this something you are interested in? If so I can submit a patch.
Thank you