Dear list,
I’ve recently made the switch from external-program to uiop/run-program::%run-program for asynchronous process execution after I read that its interface should remain essentially stable. I’ve also had to use uiop/run-program::%wait-process-result although I’m not sure if its interface in turn as subject to the same close-to-guarantee. So far the two are serving me well and I’m not looking back.
I ended up writing two functions that I needed because uiop/run-program does not currently provide such functionality while external-program did.
I’m sometimes interested in testing whether a process is running; I use the following function for that:
(defun process-running-p (process-info)
(let ((process (getf process-info :process)))
#+clozure (eq :running (ccl:external-process-status process))
#+cmu (eq :running (ext:process-status process))
#+ecl (eq :running (ext:external-process-status process))
#+mkcl (eq :running (mk-ext:process-status process))
#+sbcl (eq :running (sb-ext:process-status process))
#-(or clozure cmu ecl mkcl sbcl)
(error "Cannot determine if a process is running.")))
Maybe something like this could be incorporated into UIOP as well? (or a function that returns the process status, or a function that checks that a process is alive, etc.)
Sometimes, I also want to terminate a process before it finishes. To that end, I use the following:
(alexandria:define-constant +kill-signal+ 9 :test #'=)
(alexandria:define-constant +term-signal+ 15 :test #'=)
(defun terminate-process (process-info &key force)
(let ((process (getf process-info :process))
(sig (if force +kill-signal+ +term-signal+)))
#+allegro (progn ; FIXME: untested
#+os-unix (excl.osi:kill process sig)
#+os-windows (uiop/run-program::%run-program
(format nil "taskkill /f /pid ~a" process)
:wait t)
#-(or os-unix os-windows) (error "Cannot terminate a process.")
(sys:reap-os-subprocess :pid process))
#+clozure (ccl:signal-external-process process sig :error-if-exited nil)
#+cmu (ext:process-kill process sig)
#+sbcl (sb-ext:process-kill process sig)
#+scl (ext:process-kill process sig) ; FIXME: untested
#+mkcl (mk-ext:terminate-process process :force force)
#-(or allegro clozure cmu mkcl sbcl) (error "Cannot terminate a process.")))
This is a special case of a more general signalling facility that many lisps have but which from my understanding can only work on unix. mkcl does not provide such a facility but it does provide a terminate-process function that works on windows, too. The Allegro CL documentation states that one should run (format nil "taskkill /f /pid ~a" process) on such platforms, which could also be done with other lisps, assuming that the PID is known or can be extracted from the process. Maybe a function of this type could be incorporated into UIOP as well?
Elias Pipping