emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [RFC] Gnus generalized search, part II


From: Eric Abrahamsen
Subject: Re: [RFC] Gnus generalized search, part II
Date: Sun, 30 Apr 2017 10:46:33 -0700
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/26.0.50 (gnu/linux)

Eric Abrahamsen <address@hidden> writes:

> Eli Zaretskii <address@hidden> writes:
>
> [...]
>
>>> Ideally there would be a message noting which search process was
>>> abandoned, which is another reason to use condition-case.
>>
>> You mean condition-case in the thread function?
>
> My original assumptions about how things work have mostly turned out
> wrong. So sure, inside the thread function! I need to set up some dummy
> shell programs and test this.

I finally got time to test this. I'm attaching a python script that I
used as the external process, and pasting below the code chunk I used
for testing. This is with emacs -Q, built from master this morning. I
opened a window on each of the three process buffers, and watched the
results come in. I'm not sure the `redisplay's are necessary, or a valid
measure of process response time, but it helped with eyeballing it.

Notes:

1. At first, I made the dumb mistake of writing "(dolist (t threads)" in
   the final loop. This caused emacs to segfault, and output the
   "attempt to set a constant" error on the command line. Obviously this
   is wrong, but it probably shouldn't segfault.
2. I tweaked the sleep time parameters in various ways, but so far as I
   can tell, output was returned correctly in all cases, even when the
   first thread was given the longest sleep time. When the earlier
   threads had shorter timeouts, sometimes the redisplay showed output
   coming in to their buffer buffer, sometimes it didn't. For my
   purposes this doesn't matter.
3. Keyboard quit does nothing at all. Nothing is interrupted, everything
   returns as normal.

So I played a bit with quitting. First, in the final dolist, I wrapped
each `thread-join' in a condition-case, which caught quit and used
`thread-signal' to send the quit to the thread.

The result was that the `thread-join' was quit, but not the thread or
its process. Ie, emacs stopped waiting on that thread and moved on to
the next one, but the process output still came in, and was inserted
into the correct buffer. Not too surprising, since the thread function
itself doesn't have any reason to pay attention to 'quit. I suppose that
this is okay in this setup, because the buffer has to exist: if the
buffer were deleted after the thread-join loop, the process would also
die.

But what about my actual use-case, where each thread is appending to the
value of a let-bound variable that is closed over in the thread
function? Say the longest thread-join is quit, the shorter thread-joins
return, and execution continues on in the main thread. We move out of
scope for the let-bound return variable, and then the last remaining
thread tries to set that variable. I'm guessing it'll segfault, but I
didn't try.

Then I added a second condition-case inside each thread function,
wrapping the `accept-process-output' call, catching quit, and using it
to call `kill-process' on "proc". So a keyboard quit gets first sent to
the thread function, and then on to the thread process. That behaved
pretty much the way I hoped it would, more or less. It was a crapshoot
which thread/process got killed, but they did get killed. Sometimes I
had to hit "C-g" several times before anything happened though. I wonder
if messing with `with-local-quit' or something could make that more
predictable.

Anyway, I found all this interesting -- hope it's useful to someone
else.


#+BEGIN_SRC emacs-lisp
(setq lexical-binding t)
(defvar test-threads)
(defvar thread-test-prog)
;; Name of thread, process buffer, seconds for thread-test-prog to
;; sleep.
(setq test-threads `(("one" ,(get-buffer-create "*thread one*") "2")
                     ("two" ,(get-buffer-create "*thread two*") "10")
                     ("three" ,(get-buffer-create "*thread three*") "3")))

(setq thread-test-prog (expand-file-name "~/.bin/threadtest.py"))

(let ((threads
       (mapcar
        (lambda (el)
          (make-thread
           (lambda ()
             (let ((proc (start-process
                          (car el) (cadr el) thread-test-prog
                          "-t" (car el) "-s" (caddr el))))
               (accept-process-output proc)))
           (car el)))
        test-threads)))
  (dolist (el test-threads)
    (with-current-buffer (cadr el)
      (erase-buffer)))
  (dolist (th threads)
    (redisplay)
    (thread-join th)
    (redisplay)))
#+END_SRC

Attachment: threadtest.py
Description: Text Data


reply via email to

[Prev in Thread] Current Thread [Next in Thread]