Skip to content

GitLab

  • Menu
Projects Groups Snippets
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
  • A asdf
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 51
    • Issues 51
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 18
    • Merge requests 18
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • asdf
  • asdf
  • Wiki
  • UIOP Relatively Well Supported

Last edited by Elias Pipping Sep 22, 2017
Page history

UIOP Relatively Well Supported

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 implementations
### 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 implementations
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:
(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))

Note: Output of this code was captured on a machine where !83 had already been merged into master.

Clone repository
  • Frequently asked questions
  • UIOP Relatively Well Supported
  • Uiop hopelessly unportable
  • Home
  • uiop launch program sample code