Sleeping process not reported as sleeping

Elias Pipping pipping.elias at icloud.com
Wed Aug 3 20:52:34 UTC 2016


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)))




More information about the ecl-devel mailing list