Dear list,
I’m trying to find out how different lisp compilers handle external processes(*). As a part of that, I’ve created a short piece of code that launches an external process, sends it SIGSTOP, asks its about its well-being, and allows its to go about its business again by sending SIGCONT.
I would expect that ext:external-process-status consequently reports
(1) :running before SIGSTOP is sent (2) then :stopped (3) then :running again once SIGCONT was received (4) and finally :exited.
Indeed, that is what `ps` would do if you ran it on the command line (so I’ve added that to the example for comparison). Here’s the output of my script:
external status: [S] (expected: [S]) internal status: RUNNING (expected: running) external status: [T] (expected: [T]) internal status: RUNNING (expected: stopped) external status: [S] (expected: [S]) internal status: RUNNING (expected: running) external status: [ ] (expected: [] or [Z]) internal status: EXITED (expected: exited)
My expectations aren’t met in (2) and (3): Even though according to
https://common-lisp.net/project/ecl/manual/rn01re63.html
the status of a process can be :stopped, and the process is clearly stopped, it is not reported as such.
So I’d like to ask: Is this a bug or intentional?
Elias Pipping
(*) I’ve already sent very similar messages to openmcl-devel and sbcl-devel.
PS: Here’s the script that I used (the aforementioned messages used an earlier version):
;; careful with cmucl. it doesn't actually sleep when external processes ;; are around https://gitlab.common-lisp.net/cmucl/cmucl/issues/26 #+clozure (use-package :ccl) #+sbcl (use-package :sb-ext) #+cmu (use-package :ext)
#+clozure (setf (fdefinition 'process-output) #'external-process-output-stream) #+ecl (setf (fdefinition 'process-output) #'ext:external-process-output) #+ecl (setf (fdefinition 'run-program) #'(lambda (&rest rest) (nth-value 2 (apply #'ext:run-program rest))))
(defconstant +sigstop+ #+clozure (symbol-value (read-from-string "#$SIGSTOP")) #+cmu (unix:unix-signal-number :sigstop) #+ecl ext:+sigstop+ #+sbcl (progn (require :sb-posix) (symbol-value (find-symbol (symbol-name :sigstop) (find-package :sb-posix))))) (defconstant +sigtstp+ #+clozure (symbol-value (read-from-string "#$SIGTSTP")) #+cmu (unix:unix-signal-number :sigtstp) #+ecl ext:+sigtstp+ #+sbcl (progn (require :sb-posix) (symbol-value (find-symbol (symbol-name :sigtstp) (find-package :sb-posix))))) (defconstant +sigcont+ #+clozure (symbol-value (read-from-string "#$SIGCONT")) #+cmu (unix:unix-signal-number :sigcont) #+ecl ext:+sigcont+ #+sbcl (progn (require :sb-posix) (symbol-value (find-symbol (symbol-name :sigcont) (find-package :sb-posix)))))
(defun internal-status (process) #+clozure (external-process-status process) #+(or sbcl cmu) (process-status process) #+ecl (ext:external-process-status process))
(defun external-kill (pid signal) (run-program "/usr/bin/env" (list "kill" (format nil "-~a" signal) (format nil "~a" pid))))
;; ecl does not support writing to a string stream (defun external-status (pid) (let* ((arg-list (list "ps" "-h" "-p" (format nil "~a" pid) "-o" "state")) (process (run-program "/usr/bin/env" arg-list :output :stream)) (output (process-output process)) ; we expect a single letter (target (make-string 1))) (read-sequence target output) target))
(defun get-pid (process) #+clozure (ccl::external-process-pid process) #+ecl (ext:external-process-pid process) #+(or sbcl cmu) (process-pid process))
(let* ((p (run-program "/usr/bin/env" '("sleep" "3") :wait nil)) (pid (get-pid p))) (format t "external status: [~a] (expected: [S])~%" (external-status pid)) (format t "internal status: ~a (expected: running)~%" (internal-status p))
(external-kill pid +sigstop+) (sleep 1) (format t "external status: [~a] (expected: [T])~%" (external-status pid)) (format t "internal status: ~a (expected: stopped)~%" (internal-status p))
(external-kill pid +sigcont+) (sleep 1) (format t "external status: [~a] (expected: [S])~%" (external-status pid)) (format t "internal status: ~a (expected: running)~%" (internal-status p))
(sleep 3) (format t "external status: [~a] (expected: [] or [Z])~%" (external-status pid)) (format t "internal status: ~a (expected: exited)~%" (internal-status p)))