|
|
# `uiop:process-alive-p` and `uiop:wait-process`
|
|
|
|
|
|
The old UNIX C function `waitpid` teaches us that a process can basically be in one of five states:
|
|
|
- `:running:`
|
|
|
- `:stopped:` (+code)
|
|
|
- `:continued:`
|
|
|
- `:exited:` (+code)
|
|
|
- `:signaled:` (+code)
|
|
|
|
|
|
Few lisp implementations of common lisp expose all this completely through a single function named `process-status`. One can select a few helpful subquestions, though:
|
|
|
1. Is the process `:running:`, `:stopped:` or `:continued:` (and thus alive)?
|
|
|
2. If the process is no longer alive, did it exit or signal and which code?
|
|
|
|
|
|
The former would be answered by the function `process-alive-p` which some implementations provide; the latter second would answered by a function `wait-process`.
|
|
|
|
|
|
Because a portability layer like UIOP would have a very hard time giving out reliable `process-status` information, such a function is called `%process-statatus` in UIOP and not exported. Instead, the user is hoped to get as much as possible done though the use of the
|
|
|
portable functions `uiop:process-alive-p` and `uiop:wait-process`. Here's how:
|
|
|
|
|
|
We take the example of two separate processes, one of which is terminated via signal 15 (SIGTERM), while the other is allowed to exit and does so with an exit status of 143.
|
|
|
This combination of numbers was unintentionally chosen such because dying from signal 15 is typically reported as exiting with exit-code 143 = 128 + 15. On many implementations, we can actually decide these cases, though, which might be of interest to the user.
|
|
|
|
|
|
All of this is illustrated by blocks that look like this in the following output:
|
|
|
```
|
|
|
### abcl-1.5.0-fasl43-linux-x64
|
|
|
T | NOT-IMPLEMENTED
|
|
|
T | NOT-IMPLEMENTED
|
|
|
NIL, 143 | NOT-IMPLEMENTED
|
|
|
NIL, 143 | NOT-IMPLEMENTED
|
|
|
------------- | ---------------
|
|
|
NIL, 143 | NOT-IMPLEMENTED
|
|
|
NIL, 143 | NOT-IMPLEMENTED
|
|
|
```
|
|
|
The leading T/NIL corresponds to what `uiop:process-alive-p` reports for each process. At the top we have the the one that tirst ran and was then terminated by signal 15. At the bottom, we have the process that exited with code 143 of its own volition. Finally, the right column of the table tells us that `%process-status` is left entirely unimplemented on this implementation (abcl-1.5.0-fasl43-linux-x64). But nearly all implementation perform better in this department; take a look at this, for example:
|
|
|
```
|
|
|
### sbcl-1.3.21-linux-x64
|
|
|
T | RUNNING
|
|
|
T | RUNNING
|
|
|
NIL, 143, 15 | SIGNALED, 15
|
|
|
NIL, 143, 15 | SIGNALED, 15
|
|
|
------------- | ---------------
|
|
|
NIL, 143 | EXITED, 143
|
|
|
NIL, 143 | EXITED, 143
|
|
|
```
|
|
|
Here we see that `sbcl-1.3.21-linux-x64` does implement `%process-status` quite well and it can also distinguish the cases "signaled with code 15" and "exited with code 143" through the one/two numbers `uiop:wait-process` returns.
|
|
|
|
|
|
Here now, is the complete code:
|
|
|
|
|
|
- The output from running the test on a few platforms
|
|
|
|
|
|
```
|
|
|
### abcl-1.5.0-fasl43-linux-x64
|
|
|
T | NOT-IMPLEMENTED
|
|
|
T | NOT-IMPLEMENTED
|
|
|
NIL, 143 | NOT-IMPLEMENTED
|
|
|
NIL, 143 | NOT-IMPLEMENTED
|
|
|
------------- | ---------------
|
|
|
NIL, 143 | NOT-IMPLEMENTED
|
|
|
NIL, 143 | NOT-IMPLEMENTED
|
|
|
### acl-10.1-linux-x86
|
|
|
T | RUNNING
|
|
|
T | RUNNING
|
|
|
NIL, 143, 15 | SIGNALED, 15
|
|
|
NIL, 143, 15 | SIGNALED, 15
|
|
|
------------- | ---------------
|
|
|
NIL, 143 | EXITED, 143
|
|
|
NIL, 143 | EXITED, 143
|
|
|
### ccl-1.11-f96-linux-x86
|
|
|
T | RUNNING
|
|
|
T | RUNNING
|
|
|
NIL, 143, 15 | SIGNALED, 15
|
|
|
NIL, 143, 15 | SIGNALED, 15
|
|
|
------------- | ---------------
|
|
|
NIL, 143 | EXITED, 143
|
|
|
NIL, 143 | EXITED, 143
|
|
|
### cmu-20c_release-20c__20c_unicode_-linux-x86
|
|
|
T | RUNNING
|
|
|
T | RUNNING
|
|
|
NIL, 143, 15 | SIGNALED, 15
|
|
|
NIL, 143, 15 | SIGNALED, 15
|
|
|
------------- | ---------------
|
|
|
NIL, 143 | EXITED, 143
|
|
|
NIL, 143 | EXITED, 143
|
|
|
### cmu-21b__21b_unicode_-linux-x86
|
|
|
T | RUNNING
|
|
|
T | RUNNING
|
|
|
NIL, 143, 15 | SIGNALED, 15
|
|
|
NIL, 143, 15 | SIGNALED, 15
|
|
|
------------- | ---------------
|
|
|
NIL, 143 | EXITED, 143
|
|
|
NIL, 143 | EXITED, 143
|
|
|
### cmu-snapshot-2017-04-42-g7f3040a7e__21b_unicode_-linux-x86
|
|
|
T | RUNNING
|
|
|
T | RUNNING
|
|
|
NIL, 143, 15 | SIGNALED, 15
|
|
|
NIL, 143, 15 | SIGNALED, 15
|
|
|
------------- | ---------------
|
|
|
NIL, 143 | EXITED, 143
|
|
|
NIL, 143 | EXITED, 143
|
|
|
### ecl-16.1.3-linux-x64
|
|
|
T | RUNNING
|
|
|
T | RUNNING
|
|
|
NIL, 143, 15 | SIGNALED, 15
|
|
|
NIL, 143, 15 | SIGNALED, 15
|
|
|
------------- | ---------------
|
|
|
NIL, 143 | EXITED, 143
|
|
|
NIL, 143 | EXITED, 143
|
|
|
### ecl-16.1.3-f4feda8a-linux-x64
|
|
|
T | RUNNING
|
|
|
T | RUNNING
|
|
|
NIL, 143, 15 | SIGNALED, 15
|
|
|
NIL, 143, 15 | SIGNALED, 15
|
|
|
------------- | ---------------
|
|
|
NIL, 143 | EXITED, 143
|
|
|
NIL, 143 | EXITED, 143
|
|
|
### mkcl-1.1.10.19-2dbfa99-linux-x64
|
|
|
T | RUNNING
|
|
|
T | RUNNING
|
|
|
NIL, 143, 15 | SIGNALED, 15
|
|
|
NIL, 143, 15 | SIGNALED, 15
|
|
|
------------- | ---------------
|
|
|
NIL, 143 | EXITED, 143
|
|
|
NIL, 143 | EXITED, 143
|
|
|
### sbcl-1.3.21-linux-x64
|
|
|
T | RUNNING
|
|
|
T | RUNNING
|
|
|
NIL, 143, 15 | SIGNALED, 15
|
|
|
NIL, 143, 15 | SIGNALED, 15
|
|
|
------------- | ---------------
|
|
|
NIL, 143 | EXITED, 143
|
|
|
NIL, 143 | EXITED, 143
|
|
|
### sbcl-1.3.21.149-9e3453954-linux-x64
|
|
|
T | RUNNING
|
|
|
T | RUNNING
|
|
|
NIL, 143, 15 | SIGNALED, 15
|
|
|
NIL, 143, 15 | SIGNALED, 15
|
|
|
------------- | ---------------
|
|
|
NIL, 143 | EXITED, 143
|
|
|
NIL, 143 | EXITED, 143
|
|
|
```
|
|
|
|
|
|
- The runner (exited-vs-signaled.sh) that runs the underlying tests on a couple of platforms:
|
|
|
|
|
|
```shell
|
|
|
a=$HOME/asdf/build/asdf.lisp
|
|
|
f=$HOME/lisp-scripts/exited-vs-signaled.lisp
|
|
|
b=$HOME/lisp-installs
|
|
|
|
|
|
### Loading asdf and requiring mk-unix: the fact that "system mk-unix is out of date" is treated
|
|
|
### as a fatal error prior to ab65958cc97addf88b756dcf135b9ace76a13f02.
|
|
|
# (
|
|
|
# l=$b/mkcl-1.1.10/bin/mkcl;
|
|
|
# $l -eval '(setf *load-verbose* nil)' -eval "(load \"$a\")" -eval "(load \"$f\")" -eval '(quit)'
|
|
|
# )
|
|
|
|
|
|
(
|
|
|
l=$b/abcl-bin-1.5.0/abcl.jar
|
|
|
java -jar $l --noinform --batch --load $a --load $f
|
|
|
)
|
|
|
(
|
|
|
l=$b/acl10.1express-linux-x86/alisp
|
|
|
$l --batch -e '(setf *load-verbose* nil)' -L $a -L $f --kill
|
|
|
)
|
|
|
(
|
|
|
l=$b/ccl-1.11-linux/lx86cl
|
|
|
$l --load $a --load $f --eval '(quit)'
|
|
|
)
|
|
|
(
|
|
|
l=$b/cmucl-20c-x86-linux/bin/lisp
|
|
|
$l -quiet -batch -eval "(handler-bind ((warning #'muffle-warning)) (load \"$a\"))" -load $f -eval '(quit)'
|
|
|
)
|
|
|
(
|
|
|
l=$b/cmucl-21b-x86-linux/bin/lisp
|
|
|
$l -quiet -batch -eval "(handler-bind ((warning #'muffle-warning)) (load \"$a\"))" -load $f -eval '(quit)'
|
|
|
)
|
|
|
(
|
|
|
l=$b/cmucl-2017-04-42-g7f3040a7e-x86-linux/bin/lisp
|
|
|
$l -quiet -batch -eval "(handler-bind ((warning #'muffle-warning)) (load \"$a\"))" -load $f -eval '(quit)'
|
|
|
)
|
|
|
(
|
|
|
l=$b/ecl-16.1.3/bin/ecl
|
|
|
$l --eval '(setf *load-verbose* nil)' --eval "(load \"$a\")" --eval "(load \"$f\")" --eval '(quit)'
|
|
|
)
|
|
|
(
|
|
|
l=$b/ecl-git/bin/ecl
|
|
|
$l --eval '(setf *load-verbose* nil)' --eval "(load \"$a\")" --eval "(load \"$f\")" --eval '(quit)'
|
|
|
)
|
|
|
(
|
|
|
l=$b/mkcl-git/bin/mkcl;
|
|
|
$l -eval '(setf *load-verbose* nil)' -eval "(load \"$a\")" -eval "(load \"$f\")" -eval '(quit)'
|
|
|
)
|
|
|
(
|
|
|
l=$b/sbcl-1.3.21/bin/sbcl
|
|
|
$l --noinform --non-interactive --load $a --load $f
|
|
|
)
|
|
|
(
|
|
|
l=$b/sbcl-git/bin/sbcl
|
|
|
$l --noinform --non-interactive --load $a --load $f
|
|
|
)
|
|
|
```
|
|
|
|
|
|
- The final script (exited-vs-signaled.lisp) with all the tests:
|
|
|
|
|
|
```common-lisp
|
|
|
(defmacro call-potentially-unimplemented-function (function &rest args)
|
|
|
(let ((block-name (gensym "block")))
|
|
|
`(block ,block-name
|
|
|
(handler-bind ((uiop/utility::not-implemented-error
|
|
|
#'(lambda (c)
|
|
|
(declare (ignore c))
|
|
|
(return-from ,block-name :not-implemented))))
|
|
|
(funcall ,function ,@args)))))
|
|
|
|
|
|
(defun analyse (process)
|
|
|
(format t "~13@a | ~a~%"
|
|
|
(format nil "~{~a~^, ~}"
|
|
|
(let ((alive (uiop:process-alive-p process)))
|
|
|
(if alive
|
|
|
(list T)
|
|
|
`(,alive ,@(multiple-value-list (uiop:wait-process process))))))
|
|
|
(format nil "~{~a~^, ~}"
|
|
|
(multiple-value-list
|
|
|
(call-potentially-unimplemented-function #'uiop/launch-program::%process-status process)))))
|
|
|
|
|
|
(defun send-signal-externally (process signal)
|
|
|
(uiop:run-program (list "/bin/kill"
|
|
|
(format nil "-~a" signal)
|
|
|
(format nil "~a" (uiop:process-info-pid process)))))
|
|
|
|
|
|
(defun send->sleep->analyse->sleep->analyse (process &optional signal)
|
|
|
(when signal
|
|
|
(send-signal-externally process signal))
|
|
|
(sleep 1)
|
|
|
(analyse process)
|
|
|
(sleep 1)
|
|
|
(analyse process))
|
|
|
|
|
|
(defconstant +sigterm+
|
|
|
#+abcl (java:jcall "getNumber" (java:jnew "sun.misc.Signal" "TERM"))
|
|
|
#+allegro excl.osi:*sigterm*
|
|
|
#+clozure (symbol-value (read-from-string "#$SIGTERM"))
|
|
|
#+cmu unix:sigterm
|
|
|
#+ecl ext:+sigterm+
|
|
|
#+lispworks system::unix-sigterm
|
|
|
#+mkcl (progn (require :mk-unix)
|
|
|
(symbol-value (find-symbol (symbol-name :sigterm)
|
|
|
(find-package :mk-unix))))
|
|
|
#+sbcl (progn (require :sb-posix)
|
|
|
(symbol-value (find-symbol (symbol-name :sigterm)
|
|
|
(find-package :sb-posix)))))
|
|
|
|
|
|
(progn
|
|
|
(format t "### ~a~%" (asdf:implementation-identifier))
|
|
|
|
|
|
(let ((p-sleep (uiop:launch-program '("/bin/sleep" "5"))))
|
|
|
(send->sleep->analyse->sleep->analyse p-sleep)
|
|
|
(send->sleep->analyse->sleep->analyse p-sleep +sigterm+))
|
|
|
|
|
|
(format t "------------- | ---------------~%")
|
|
|
|
|
|
(let ((p-exit (uiop:launch-program '("/bin/sh" "-c" "exit 143"))))
|
|
|
(send->sleep->analyse->sleep->analyse p-exit))
|
|
|
|
|
|
(uiop:quit 0))
|
|
|
``` |
|
|
\ No newline at end of file |