Dear Elias,
this kind of functionality is welcome in UIOP. However, the responsibility is yours to ensure that it will work on every implementation on every platform. Please make reasonably sure it works before you submit the patch. You may contact various vendors for a test license as appropriate.
Note that there are several run-program style libraries around. If you're going to do this, I suggest you look at each and every of these libraries (notably executor and external-program) and make sure you have at least feature-parity and implementation-parity with them. Also make sure that you explicitly raise an error on unsupported implementations, at the start of every function that doesn't support them.
Also, if you are going to support these interface, you can graduate them out of % namespace (but keep the % name around for backward compatibility for a year or two).
Would you be interested in becoming official maintainer for UIOP?
—♯ƒ • François-René ÐVB Rideau •Reflection&Cybernethics• http://fare.tunes.org The trouble with opportunity is that it always comes disguised as hard work. — Herbert V. Prochnow
On Sun, Jul 31, 2016 at 1:57 PM, Elias Pipping pipping.elias@icloud.com wrote:
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