Subject: 23.4; overlapping process filter calls

From: Hendrik Tews <[email-masked]>
Date: Thu, 10 Jan 2013 11:11:42 +0100

Hi,

because Stefan Monnier asked for it
(http://lists.inf.ed.ac.uk/pipermail/proofgeneral-devel/2013/000296.html):

When a process filter does I/O (eg, process-send-string), it
might happen, that the same filter is called again for the same
process, while the first instance blocks. To reproduce, load the
code below and do M-x double-filter.

The problem is real with Coq Proof General and Prooftree. There,
Prooftree is driven from a process filter in Proof General. With
cold disk caches, it takes about 1 sec to start Prooftree (at
least on my laptops). Coq and Proof General easily fill the pipe
in that time, so that the process filter blocks inside
process-send-string. Meanwhile Coq continues to produce output
and the process filter is called again while the previous call
has not finished.

The more I think about it, I believe this is a feature. 

However, the documentation is sometimes wrong and could be
clearer about this feature:

- Section "37.9 Receiving Output from Processes" does not list
  process-send-string. How about other blocking I/O functions?

- Same in "37.9.2. Process Filter Functions"

- Same in "37.4 Creating an Asynchronous Process" ,
  process-send-string is neither waiting for input not time
  delay.

- "37.7 Sending Input to Processes" says that filters can run
  inside process-send-string, but it could be clearer about the
  point that this can also happen inside the same filter for the
  same process.

- "37.9.2 Process Filter Functions" ignores the problem
  completely. There should be a paragraph clearly stating this
  problem. Further, it would be nice, if the filter function
  example could be extended to correctly deal with this problem.

To make it easier in the future to deal with this problem, I
suggest to add a process specific flag
``process-no-concurrent-filters''. When this flag is t for a
process, Emacs accepts output from this process inside a filter
but buffers it without calling the filter. The call to the filter
is delayed until a point where no filter for this process is
running. An error is signaled, if the buffered output exceeds a
certain size.

===========================================================================
(defun double-filter ()
  (interactive)
  (setq df-process (start-process "tee" nil "/bin/cat"))
  (set-process-filter df-process 'df-filter)
  (set-process-sentinel df-process 'df-sentinel)
  (set-process-query-on-exit-flag df-process nil)
  (setq df-buf (get-buffer-create "xxxx"))
  (process-send-string df-process "1\n"))

(setq df-filter-lock nil)
(setq df-error nil)

(defun df-filter (p str)
  (unless df-error
    (with-current-buffer df-buf
      (insert (format "filter received %d bytes lock %s\n"
		      (length str) df-filter-lock)))
    (when df-filter-lock
      (setq df-error t)
      (error "recursive filter"))
    (setq df-filter-lock t)
    (setq long (make-string 4096 65))
    (process-send-string df-process long)
    (process-send-string df-process long)
    (process-send-string df-process long)
    (process-send-string df-process long)
    (process-send-string df-process long)
    (process-send-string df-process long)
    (process-send-string df-process long)
    (process-send-string df-process long)
    (setq df-filter-lock nil)))

(defun df-sentinel (p event)
  (setq df-error t)
  (with-current-buffer df-bug
    (insert "process died\n")))
==============================================================================

In GNU Emacs 23.4.1 (i486-pc-linux-gnu, GTK+ Version 2.24.10)
 of 2012-09-09 on murphy, modified by Debian
Windowing system distributor `The X.Org Foundation', version 11.0.11204000
configured using `configure  '--build' 'i486-linux-gnu' '--build' 'i486-linux-gnu' '--prefix=/usr' '--sharedstatedir=/var/lib' '--libexecdir=/usr/lib' '--localstatedir=/var/lib' '--infodir=/usr/share/info' '--mandir=/usr/share/man' '--with-pop=yes' '--enable-locallisppath=/etc/emacs23:/etc/emacs:/usr/local/share/emacs/23.4/site-lisp:/usr/local/share/emacs/site-lisp:/usr/share/emacs/23.4/site-lisp:/usr/share/emacs/site-lisp' '--with-crt-dir=/usr/lib/i386-linux-gnu' '--with-x=yes' '--with-x-toolkit=gtk' '--with-toolkit-scroll-bars' 'build_alias=i486-linux-gnu' 'CFLAGS=-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -Wall -DDEBIAN -O2' 'CPPFLAGS=-D_FORTIFY_SOURCE=2''

Important settings:
  value of $LC_ALL: nil
  value of $LC_COLLATE: nil
  value of $LC_CTYPE: nil
  value of $LC_MESSAGES: nil
  value of $LC_MONETARY: nil
  value of $LC_NUMERIC: nil
  value of $LC_TIME: nil
  value of $LANG: en_US.UTF-8
  value of $XMODIFIERS: nil
  locale-coding-system: utf-8-unix
  default enable-multibyte-characters: t

Major mode: Emacs-Lisp

Minor modes in effect:
  show-paren-mode: t
  msb-mode: t
  mouse-wheel-mode: t
  menu-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t
  column-number-mode: t
  line-number-mode: t
  transient-mark-mode: t