From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Eric Abrahamsen Newsgroups: gmane.emacs.devel Subject: Re: [RFC] Gnus generalized search, part II Date: Sun, 30 Apr 2017 10:46:33 -0700 Message-ID: <87a86x3i12.fsf@ericabrahamsen.net> References: <87zif930mt.fsf@ericabrahamsen.net> <87tw5hjnzr.fsf@hanan> <87mvb92er2.fsf@ericabrahamsen.net> <83efwkrhj1.fsf@gnu.org> <87inlw32ga.fsf@ericabrahamsen.net> <8337d0qxno.fsf@gnu.org> <87shl01bzb.fsf@ericabrahamsen.net> <83shl0p5pw.fsf@gnu.org> <8737d0ukev.fsf@ericabrahamsen.net> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Trace: blaine.gmane.org 1493574445 21033 195.159.176.226 (30 Apr 2017 17:47:25 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Sun, 30 Apr 2017 17:47:25 +0000 (UTC) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.0.50 (gnu/linux) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sun Apr 30 19:47:19 2017 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1d4swJ-0005MH-Iu for ged-emacs-devel@m.gmane.org; Sun, 30 Apr 2017 19:47:19 +0200 Original-Received: from localhost ([::1]:45435 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1d4swP-0002WG-6S for ged-emacs-devel@m.gmane.org; Sun, 30 Apr 2017 13:47:25 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:40635) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1d4svm-0002Vy-KP for emacs-devel@gnu.org; Sun, 30 Apr 2017 13:46:47 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1d4svj-0003LP-Hy for emacs-devel@gnu.org; Sun, 30 Apr 2017 13:46:46 -0400 Original-Received: from [195.159.176.226] (port=56230 helo=blaine.gmane.org) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1d4svj-0003LB-A6 for emacs-devel@gnu.org; Sun, 30 Apr 2017 13:46:43 -0400 Original-Received: from list by blaine.gmane.org with local (Exim 4.84_2) (envelope-from ) id 1d4svb-0004gk-4v for emacs-devel@gnu.org; Sun, 30 Apr 2017 19:46:35 +0200 X-Injected-Via-Gmane: http://gmane.org/ Original-Lines: 131 Original-X-Complaints-To: usenet@blaine.gmane.org Cancel-Lock: sha1:7TZpr5VpRY7cwfTZ5PgmN1/AFMs= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 195.159.176.226 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:214446 Archived-At: --=-=-= Content-Type: text/plain Eric Abrahamsen writes: > Eli Zaretskii 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 --=-=-= Content-Type: text/x-python Content-Disposition: attachment; filename=threadtest.py #!/usr/bin/env python3 import time import argparse defsecs = 3 parser = argparse.ArgumentParser() parser.add_argument("-t", "--thread") parser.add_argument("-s", "--seconds", type=int) args = parser.parse_args() if not args.seconds: args.seconds = defsecs time.sleep(args.seconds) print("Process %s output (%s)" % (args.thread, time.strftime("%H:%M:%S"))) --=-=-=--