Subject: 29.0.50; stop-process on pipes

From: Helmut Eller <[email-masked]>
Date: Wed, 13 Oct 2021 11:20:01 +0200

I would like to request this feature: stop-process, when called with a
sub-process that is connected via pipes, should use delete_read_fd.  It
should basically do the same as for sockets.

Currently, stop-process uses some difficult to understand logic and
eventually sends SIGSTOP to the process.  This might work in theory, but
in practice it can take a long time before Emacs stops receiving output.

The code below illustrates the problem with two examples:
test-stop-process and test-signal-process.  One uses stop-process while
the other uses (signal-process 'SIGSTOP).  The output is something like
this:

  emacs -Q --batch -l stop.el -f ert-run-tests-batch-and-exit
  Running 2 tests (2021-10-13 11:00:45+0200, selector ‘t’)
  use-signals = t; my-counter = 17 buffer-size = 69672
     passed  1/2  test-signal-process (0.200925 sec)
  use-signals = nil; my-counter = 1099 buffer-size = 4501504
     passed  2/2  test-stop-process (0.201133 sec)

With signal-process, the filter function is called 17 times before the
sub-process stops sending output.

With stop-process, it takes 1099 calls and Emacs receives 4 megabytes of
output.  These numbers can be even higher, if the argument to sleep-for
is larger.

If we would use delete_read_fd, then the filter function would be called
exactly once.  At least I think so.  That would, of course, be much more
desirable.

Helmut

(ert-deftest test-stop-process () (run-test nil))

(ert-deftest test-signal-process () (run-test t))

(defun my-start-process ()
  (let ((buffer (generate-new-buffer " some-process")))
    (make-process :command '("cat" "/dev/zero")
                  :name (buffer-name buffer)
                  :buffer buffer
                  :filter #'my-filter
                  :connection-type 'pipe)))

(defvar my-counter 0)

(defun my-filter (proc string)
  (setq my-counter (1+ my-counter))
  (with-current-buffer (process-buffer proc)
    (goto-char (point-max))
    (insert string)
    ;; (message "stopping: %s %s %s" (buffer-size)
    ;;         (process-id proc) (process-status proc))
    (cond ((process-get proc 'use-signals)
           (signal-process proc 'SIGSTOP))
          (t
           (stop-process proc)))))

(defun run-test (use-signals)
  (let ((proc (my-start-process))
        (my-counter 0))
    (process-put proc 'use-signals use-signals)
    (sleep-for 0.2)
    (while (= my-counter 0)
      (accept-process-output p 0.1))
    (message "use-signals = %s; my-counter = %s buffer-size = %s" 
             use-signals my-counter
             (buffer-size (process-buffer proc)))))

In GNU Emacs 29.0.50 (build 3, x86_64-pc-linux-gnu, GTK+ Version 3.24.24, cairo version 1.16.0)
 of 2021-10-11 built on caladan
Repository revision: 2810fe6bfca182e4376d818b5510507d5ff7e1b5
Repository branch: master
Windowing system distributor 'The X.Org Foundation', version 11.0.12011000
System Description: Debian GNU/Linux 11 (bullseye)

Configured using:
 'configure --with-xpm=ifavailable --with-jpeg=ifavailable
 --with-gif=ifavailable --with-tiff=ifavailable'

Configured features:
CAIRO DBUS FREETYPE GLIB GMP GNUTLS GSETTINGS HARFBUZZ LIBSELINUX
LIBSYSTEMD LIBXML2 MODULES NOTIFY INOTIFY PDUMPER PNG SECCOMP SOUND
THREADS TOOLKIT_SCROLL_BARS X11 XDBE XIM GTK3 ZLIB

Important settings:
  value of $LANG: C.UTF-8
  locale-coding-system: utf-8-unix