extending uiop/run-program

Elias Pipping pipping.elias at icloud.com
Sun Jul 31 17:57:16 UTC 2016


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


More information about the asdf-devel mailing list