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