* make-thread with lambda form instead of function symbol @ 2017-04-16 16:05 Eric Abrahamsen 2017-04-16 16:21 ` Noam Postavsky 2017-04-17 1:12 ` Eric Abrahamsen 0 siblings, 2 replies; 17+ messages in thread From: Eric Abrahamsen @ 2017-04-16 16:05 UTC (permalink / raw) To: emacs-devel Okay, one more thread question... I'm trying to do something that seems like it would be a normal use case: spawn a series of threads which call the same function using different external processes. Practically what this means is that I want to pass a function-plus-argument form to make-thread, not a function symbol. Something like: (let* ((results) (sources '(source1 source2)) (threads (mapcar (lambda (s) (make-thread (funcall (lambda () (push (get-stuff-from-source s) results))))) sources))) (mapc #'thread-join threads) results) The (funcall (lambda () thing was the only way I could get anything but nil out of the thread functions. I think I'm fooling myself, though: so far as I can tell, `get-stuff-from-source' is fully evaluated before the thread is made, and nothing at all happens during the #'thread-join loop. Is it possible to give make-thread anything but a function symbol? The only other thing I could think of was looping over the sources and making ad-hoc symbols: (fset (make-symbol (format "%s-dummy-function" (source-name source))) (lambda () (push (get-stuff-from-source source) results))) That seems ugly, but perhaps not that bad. Thanks in advance, Eric ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: make-thread with lambda form instead of function symbol 2017-04-16 16:05 make-thread with lambda form instead of function symbol Eric Abrahamsen @ 2017-04-16 16:21 ` Noam Postavsky 2017-04-16 18:11 ` Eric Abrahamsen 2017-04-17 1:12 ` Eric Abrahamsen 1 sibling, 1 reply; 17+ messages in thread From: Noam Postavsky @ 2017-04-16 16:21 UTC (permalink / raw) To: Eric Abrahamsen; +Cc: Emacs developers On Sun, Apr 16, 2017 at 12:05 PM, Eric Abrahamsen <eric@ericabrahamsen.net> wrote: > I'm trying to do something that seems like it would be a normal use > case: spawn a series of threads which call the same function using > different external processes. Practically what this means is that I want > to pass a function-plus-argument form to make-thread, not a function > symbol. Something like: > > (let* ((results) > (sources '(source1 source2)) > (threads > (mapcar > (lambda (s) > (make-thread > (funcall > (lambda () > (push (get-stuff-from-source s) results))))) > sources))) > (mapc #'thread-join threads) > results) > > The (funcall (lambda () thing was the only way I could get anything but > nil out of the thread functions. I think I'm fooling myself, though: so > far as I can tell, `get-stuff-from-source' is fully evaluated before the > thread is made, and nothing at all happens during the #'thread-join > loop. Just drop the funcall: (make-thread (lambda () ...)) should do what you want, assuming you have lexical-binding set (if not, you can construct a lambda-list with backquote or similar). ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: make-thread with lambda form instead of function symbol 2017-04-16 16:21 ` Noam Postavsky @ 2017-04-16 18:11 ` Eric Abrahamsen 2017-04-16 18:44 ` Noam Postavsky 0 siblings, 1 reply; 17+ messages in thread From: Eric Abrahamsen @ 2017-04-16 18:11 UTC (permalink / raw) To: emacs-devel Noam Postavsky <npostavs@users.sourceforge.net> writes: > On Sun, Apr 16, 2017 at 12:05 PM, Eric Abrahamsen > <eric@ericabrahamsen.net> wrote: >> I'm trying to do something that seems like it would be a normal use >> case: spawn a series of threads which call the same function using >> different external processes. Practically what this means is that I want >> to pass a function-plus-argument form to make-thread, not a function >> symbol. Something like: >> >> (let* ((results) >> (sources '(source1 source2)) >> (threads >> (mapcar >> (lambda (s) >> (make-thread >> (funcall >> (lambda () >> (push (get-stuff-from-source s) results))))) >> sources))) >> (mapc #'thread-join threads) >> results) >> >> The (funcall (lambda () thing was the only way I could get anything but >> nil out of the thread functions. I think I'm fooling myself, though: so >> far as I can tell, `get-stuff-from-source' is fully evaluated before the >> thread is made, and nothing at all happens during the #'thread-join >> loop. > > Just drop the funcall: (make-thread (lambda () ...)) should do what > you want, assuming you have lexical-binding set (if not, you can > construct a lambda-list with backquote or similar). Thanks for the response. The first thing I learned here was that lexical-binding was nil in *scratch*, but t in the source file I'm writing -- not a great testing setup. I'm still not seeing the results I expect, though. Here's a dumb test: (setq lexical-binding t) (let ((threads (mapcar (lambda (el) (make-thread (lambda () (push (cl-incf el) results)))) '(1 2 3))) results) (mapc #'thread-join threads) results) This gives me nil. (Incidentally, if I put this in a function and edebug it, it tells me edebug will stop at the next break point, and then enters a level of recursive editing I can't escape from: C-M-c gives me "No catch for tag: exit, nil".) Should the above example work? Thanks again, Eric ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: make-thread with lambda form instead of function symbol 2017-04-16 18:11 ` Eric Abrahamsen @ 2017-04-16 18:44 ` Noam Postavsky 2017-04-16 20:02 ` Eric Abrahamsen 0 siblings, 1 reply; 17+ messages in thread From: Noam Postavsky @ 2017-04-16 18:44 UTC (permalink / raw) To: Eric Abrahamsen; +Cc: Emacs developers On Sun, Apr 16, 2017 at 2:11 PM, Eric Abrahamsen <eric@ericabrahamsen.net> wrote: > > (setq lexical-binding t) > > (let ((threads > (mapcar > (lambda (el) > (make-thread > (lambda () > (push (cl-incf el) results)))) > '(1 2 3))) > results) > (mapc #'thread-join threads) > results) > > This gives me nil. > > (Incidentally, if I put this in a function and edebug it, it tells me > edebug will stop at the next break point, and then enters a level of > recursive editing I can't escape from: C-M-c gives me "No catch for tag: > exit, nil".) > > Should the above example work? No, check the compile warnings: a.el:7:33:Warning: reference to free variable ‘results’ a.el:9:7:Warning: assignment to free variable ‘results’ Not sure about the edebug thing, probably it doesn't handle cross-thread stepping. The below returns (2 3 4) or sometimes (3 4 2). (let* ((results nil) (threads (mapcar (lambda (el) (make-thread (lambda () (push (cl-incf el) results)))) '(1 2 3)))) (mapc #'thread-join threads) results) ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: make-thread with lambda form instead of function symbol 2017-04-16 18:44 ` Noam Postavsky @ 2017-04-16 20:02 ` Eric Abrahamsen 0 siblings, 0 replies; 17+ messages in thread From: Eric Abrahamsen @ 2017-04-16 20:02 UTC (permalink / raw) To: emacs-devel Noam Postavsky <npostavs@users.sourceforge.net> writes: > On Sun, Apr 16, 2017 at 2:11 PM, Eric Abrahamsen > <eric@ericabrahamsen.net> wrote: >> >> (setq lexical-binding t) >> >> (let ((threads >> (mapcar >> (lambda (el) >> (make-thread >> (lambda () >> (push (cl-incf el) results)))) >> '(1 2 3))) >> results) >> (mapc #'thread-join threads) >> results) >> >> This gives me nil. >> >> (Incidentally, if I put this in a function and edebug it, it tells me >> edebug will stop at the next break point, and then enters a level of >> recursive editing I can't escape from: C-M-c gives me "No catch for tag: >> exit, nil".) >> >> Should the above example work? > > No, check the compile warnings: > > a.el:7:33:Warning: reference to free variable ‘results’ > a.el:9:7:Warning: assignment to free variable ‘results’ Aha! That makes sense now that I see it. The thread function starts executing immediately, so of course it needs to be able to see "results". Thanks for that. > Not sure about the edebug thing, probably it doesn't handle > cross-thread stepping. I can imagine it would be complicated. Thanks again, Eric ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: make-thread with lambda form instead of function symbol 2017-04-16 16:05 make-thread with lambda form instead of function symbol Eric Abrahamsen 2017-04-16 16:21 ` Noam Postavsky @ 2017-04-17 1:12 ` Eric Abrahamsen 2017-04-17 1:46 ` Noam Postavsky ` (2 more replies) 1 sibling, 3 replies; 17+ messages in thread From: Eric Abrahamsen @ 2017-04-17 1:12 UTC (permalink / raw) To: emacs-devel [-- Attachment #1: Type: text/plain, Size: 1878 bytes --] Eric Abrahamsen <eric@ericabrahamsen.net> writes: > Okay, one more thread question... Well, here's the long story: I'm messing with Gnus's nnir search routines, trying to make a general search query language that can be translated into backend-specific queries depending on which groups you've selected to search. The idea is you could mark both an IMAP group and an nnmaildir group (indexed by notmuch), enter a single search query, the query would be transformed into backend-appropriate versions, and you'd get one search group containing messages returned by backends. So then I figured: if we're searching different backends at once, and each backend does its heavy lifting in an external process, then threads would allow those processes to do their work concurrently, and results could come back faster. (If I can get this to work, I hope to look at getting Gnus to fetch new news concurrently, as well.) But! My current implementation is causing Emacs to segfault. The actual function looks like this: (defun nnir-run-query (specs) (let* ((results []) (threads (mapcar (lambda (x) (let* ((server (car x)) (search-engine (nnir-server-to-search-engine server))) (make-thread (lambda () (setq results (vconcat (nnir-run-search search-engine server (cdr (assq 'nnir-query-spec specs)) (cadr x)) results)))))) (cdr (assq 'nnir-group-spec specs))))) (mapc #'thread-join threads) results)) I'm testing with a single IMAP server query (ie, only one thread is being created). The nnir-run-search function for the IMAP backend ends up calling nnimap-send-command--> nnimap-wait-for-response--> nnheader-accept-process-output--> accept-process-output, so I'm expecting that's where the thread yields. I'm attaching the traceback here. Dunno if it's something I've done wrong... Thanks, Eric [-- Attachment #2: log.txt --] [-- Type: text/plain, Size: 6545 bytes --] #0 0x000000000058879c in terminate_due_to_signal (sig=6, backtrace_limit=2147483647) at emacs.c:363 #1 0x000000000061dbf4 in die (msg=0x74e3fd "STRINGP (a)", file=0x74e330 "lisp.h", line=1276) at alloc.c:7339 #2 0x0000000000582dfd in XSTRING (a=...) at lisp.h:1276 #3 0x0000000000582e44 in SDATA (string=...) at lisp.h:1327 #4 0x000000000069f953 in Faccept_process_output (process=..., seconds=..., millisec=..., just_this_one=...) at process.c:4566 #5 0x00000000006430f7 in funcall_subr (subr=0xd74628 <Saccept_process_output>, numargs=3, args=0x7fffe5987f10) at eval.c:2826 #6 0x0000000000642bda in Ffuncall (nargs=4, args=0x7fffe5987f08) at eval.c:2743 #7 0x0000000000691dd2 in exec_byte_code (bytestr=..., vector=..., maxdepth=..., args_template=..., nargs=0, args=0x0) at bytecode.c:641 #8 0x0000000000643cb9 in funcall_lambda (fun=..., nargs=1, arg_vector=0x577f1f5) at eval.c:3021 #9 0x0000000000642c0e in Ffuncall (nargs=2, args=0x7fffe5988638) at eval.c:2745 #10 0x0000000000691dd2 in exec_byte_code (bytestr=..., vector=..., maxdepth=..., args_template=..., nargs=0, args=0x0) at bytecode.c:641 #11 0x0000000000643cb9 in funcall_lambda (fun=..., nargs=1, arg_vector=0x58b7325) at eval.c:3021 #12 0x0000000000642c0e in Ffuncall (nargs=2, args=0x7fffe5988e58) at eval.c:2745 #13 0x0000000000691dd2 in exec_byte_code (bytestr=..., vector=..., maxdepth=..., args_template=..., nargs=0, args=0x0) at bytecode.c:641 #14 0x0000000000643cb9 in funcall_lambda (fun=..., nargs=1, arg_vector=0x58b71ed) at eval.c:3021 #15 0x0000000000642c0e in Ffuncall (nargs=2, args=0x7fffe5989558) at eval.c:2745 #16 0x0000000000691dd2 in exec_byte_code (bytestr=..., vector=..., maxdepth=..., args_template=..., nargs=0, args=0x0) at bytecode.c:641 #17 0x0000000000643cb9 in funcall_lambda (fun=..., nargs=3, arg_vector=0x58b713d) at eval.c:3021 #18 0x0000000000642c0e in Ffuncall (nargs=4, args=0x7fffe5989ca8) at eval.c:2745 #19 0x0000000000691dd2 in exec_byte_code (bytestr=..., vector=..., maxdepth=..., args_template=..., nargs=0, args=0x0) at bytecode.c:641 #20 0x0000000000643cb9 in funcall_lambda (fun=..., nargs=2, arg_vector=0x58b6d9d) at eval.c:3021 #21 0x0000000000643418 in apply_lambda (fun=..., args=..., count=22) at eval.c:2880 #22 0x00000000006416da in eval_sub (form=...) at eval.c:2264 #23 0x000000000063c0c3 in Fif (args=...) at eval.c:403 #24 0x0000000000641126 in eval_sub (form=...) at eval.c:2172 #25 0x000000000063ee5d in internal_lisp_condition_case (var=..., bodyform=..., handlers=...) at eval.c:1295 #26 0x000000000063e912 in Fcondition_case (args=...) at eval.c:1221 #27 0x0000000000641126 in eval_sub (form=...) at eval.c:2172 #28 0x000000000063c394 in Fprogn (body=...) at eval.c:449 #29 0x000000000063dff6 in Flet (args=...) at eval.c:963 #30 0x0000000000641126 in eval_sub (form=...) at eval.c:2172 #31 0x000000000063c394 in Fprogn (body=...) at eval.c:449 #32 0x0000000000643c19 in funcall_lambda (fun=..., nargs=1, arg_vector=0x0) at eval.c:3014 #33 0x0000000000642d10 in Ffuncall (nargs=2, args=0x7fffe598adf0) at eval.c:2757 #34 0x0000000000642577 in call1 (fn=..., arg1=...) at eval.c:2605 #35 0x00000000006501f6 in mapcar1 (leni=1, vals=0x7fffe598aea0, fn=..., seq=...) at fns.c:2471 #36 0x0000000000650615 in Fmapcar (function=..., sequence=...) at fns.c:2523 #37 0x000000000064150d in eval_sub (form=...) at eval.c:2222 #38 0x000000000063c394 in Fprogn (body=...) at eval.c:449 #39 0x000000000063e450 in internal_catch (tag=..., func=0x63c33d <Fprogn>, arg=...) at eval.c:1091 #40 0x000000000063e404 in Fcatch (args=...) at eval.c:1068 #41 0x0000000000641126 in eval_sub (form=...) at eval.c:2172 #42 0x000000000064129a in eval_sub (form=...) at eval.c:2184 #43 0x000000000063c394 in Fprogn (body=...) at eval.c:449 #44 0x000000000063dff6 in Flet (args=...) at eval.c:963 #45 0x0000000000641126 in eval_sub (form=...) at eval.c:2172 #46 0x000000000063c394 in Fprogn (body=...) at eval.c:449 #47 0x000000000062cb7b in Fsave_excursion (args=...) at editfns.c:1053 #48 0x0000000000641126 in eval_sub (form=...) at eval.c:2172 #49 0x000000000063c394 in Fprogn (body=...) at eval.c:449 #50 0x0000000000641126 in eval_sub (form=...) at eval.c:2172 #51 0x000000000063c394 in Fprogn (body=...) at eval.c:449 #52 0x0000000000643c19 in funcall_lambda (fun=..., nargs=4, arg_vector=0x0) at eval.c:3014 #53 0x0000000000642d10 in Ffuncall (nargs=5, args=0x7fffe598bb50) at eval.c:2757 #54 0x0000000000641eb0 in Fapply (nargs=3, args=0x7fffe598bd80) at eval.c:2374 #55 0x0000000000642f81 in funcall_subr (subr=0xd719a8 <Sapply>, numargs=3, args=0x7fffe598bd80) at eval.c:2798 #56 0x0000000000642bda in Ffuncall (nargs=4, args=0x7fffe598bd78) at eval.c:2743 #57 0x0000000000691dd2 in exec_byte_code (bytestr=..., vector=..., maxdepth=..., args_template=..., nargs=4, args=0x7fffe598c488) at bytecode.c:641 #58 0x00000000006437e1 in funcall_lambda (fun=..., nargs=4, arg_vector=0x7fffe598c480) at eval.c:2943 #59 0x0000000000643418 in apply_lambda (fun=..., args=..., count=4) at eval.c:2880 #60 0x00000000006416da in eval_sub (form=...) at eval.c:2264 #61 0x000000000064129a in eval_sub (form=...) at eval.c:2184 #62 0x000000000063c5d8 in Fsetq (args=...) at eval.c:511 #63 0x0000000000641126 in eval_sub (form=...) at eval.c:2172 #64 0x000000000063c394 in Fprogn (body=...) at eval.c:449 #65 0x0000000000643c19 in funcall_lambda (fun=..., nargs=0, arg_vector=0x0) at eval.c:3014 #66 0x0000000000642d10 in Ffuncall (nargs=1, args=0x6117b30) at eval.c:2757 #67 0x00000000006cfe09 in invoke_thread_function () at thread.c:669 #68 0x000000000063eef9 in internal_condition_case (bfun=0x6cfde1 <invoke_thread_function>, handlers=..., hfun=0x6cfe28 <record_thread_error>) at eval.c:1324 #69 0x00000000006cff5c in run_thread (state=0x6117b10) at thread.c:708 #70 0x00007ffff01c52e7 in start_thread () at /usr/lib/libpthread.so.0 #71 0x00007fffefad454f in clone () at /usr/lib/libc.so.6 Lisp Backtrace: "accept-process-output" (0xe5987f10) "nnheader-accept-process-output" (0xe5988640) "nnimap-wait-for-response" (0xe5988e60) "nnimap-get-response" (0xe5989560) "nnimap-command" (0xe5989cb0) "nnimap-change-group" (0xe598a3c0) "if" (0xe598a6b0) "condition-case" (0xe598a940) "let" (0xe598aba0) 0x61e7760 Lisp type 3 "mapcar" (0xe598afa0) "catch" (0xe598b1f0) "apply" (0xe598b360) "let" (0xe598b5e0) "save-excursion" (0xe598b7a0) "progn" (0xe598b920) 0x660b320 Lisp type 3 "apply" (0xe598bd80) "nnir-run-search" (0xe598c480) "vconcat" (0xe598c760) "setq" (0xe598c930) 0x61e9790 Lisp type 3 ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: make-thread with lambda form instead of function symbol 2017-04-17 1:12 ` Eric Abrahamsen @ 2017-04-17 1:46 ` Noam Postavsky 2017-04-17 3:45 ` Eric Abrahamsen 2017-04-17 6:51 ` Eli Zaretskii 2017-04-17 6:59 ` Andrew Cohen 2 siblings, 1 reply; 17+ messages in thread From: Noam Postavsky @ 2017-04-17 1:46 UTC (permalink / raw) To: Eric Abrahamsen; +Cc: Emacs developers On Sun, Apr 16, 2017 at 9:12 PM, Eric Abrahamsen <eric@ericabrahamsen.net> wrote: > > (defun nnir-run-query (specs) > (let* ((results []) > (threads > (mapcar > (lambda (x) > (let* ((server (car x)) > (search-engine (nnir-server-to-search-engine server))) > (make-thread > (lambda () > (setq results > (vconcat > (nnir-run-search > search-engine > server > (cdr (assq 'nnir-query-spec specs)) > (cadr x)) > results)))))) > (cdr (assq 'nnir-group-spec specs))))) > (mapc #'thread-join threads) > results)) > > I'm testing with a single IMAP server query (ie, only one thread is > being created). The nnir-run-search function for the IMAP backend ends > up calling nnimap-send-command--> nnimap-wait-for-response--> > nnheader-accept-process-output--> accept-process-output, so I'm > expecting that's where the thread yields. > > I'm attaching the traceback here. Dunno if it's something I've done > wrong... > #4 0x000000000069f953 in Faccept_process_output (process=..., seconds=..., millisec=..., just_this_one=...) at process.c:4566 Is line process.c:4566 this one? error ("Attempt to accept output from process %s locked to thread %s", SDATA (proc->name), SDATA (XTHREAD (proc->thread)->name)); I guess that indicates you might be doing something wrong (though obviously Emacs shouldn't be crashing) ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: make-thread with lambda form instead of function symbol 2017-04-17 1:46 ` Noam Postavsky @ 2017-04-17 3:45 ` Eric Abrahamsen 2017-04-17 7:02 ` Eli Zaretskii 0 siblings, 1 reply; 17+ messages in thread From: Eric Abrahamsen @ 2017-04-17 3:45 UTC (permalink / raw) To: emacs-devel Noam Postavsky <npostavs@users.sourceforge.net> writes: > On Sun, Apr 16, 2017 at 9:12 PM, Eric Abrahamsen > <eric@ericabrahamsen.net> wrote: >> >> (defun nnir-run-query (specs) >> (let* ((results []) >> (threads >> (mapcar >> (lambda (x) >> (let* ((server (car x)) >> (search-engine (nnir-server-to-search-engine server))) >> (make-thread >> (lambda () >> (setq results >> (vconcat >> (nnir-run-search >> search-engine >> server >> (cdr (assq 'nnir-query-spec specs)) >> (cadr x)) >> results)))))) >> (cdr (assq 'nnir-group-spec specs))))) >> (mapc #'thread-join threads) >> results)) >> >> I'm testing with a single IMAP server query (ie, only one thread is >> being created). The nnir-run-search function for the IMAP backend ends >> up calling nnimap-send-command--> nnimap-wait-for-response--> >> nnheader-accept-process-output--> accept-process-output, so I'm >> expecting that's where the thread yields. >> >> I'm attaching the traceback here. Dunno if it's something I've done >> wrong... > >> #4 0x000000000069f953 in Faccept_process_output (process=..., seconds=..., millisec=..., just_this_one=...) at process.c:4566 > > Is line process.c:4566 this one? > > error ("Attempt to accept output from process %s locked to thread %s", > SDATA (proc->name), SDATA (XTHREAD (proc->thread)->name)); > > I guess that indicates you might be doing something wrong (though > obviously Emacs shouldn't be crashing) So perhaps an existing process can't be "moved" to another thread? Tomorrow I'll set up a notmuch-indexed server and try that -- in that case the process should be invoked and concluded within a single make-thread call, so maybe it won't raise this error. But the segfault here seems to be coming from a borked attempt to represent either the process or the thread as a string.... ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: make-thread with lambda form instead of function symbol 2017-04-17 3:45 ` Eric Abrahamsen @ 2017-04-17 7:02 ` Eli Zaretskii 2017-04-17 16:54 ` Eric Abrahamsen 0 siblings, 1 reply; 17+ messages in thread From: Eli Zaretskii @ 2017-04-17 7:02 UTC (permalink / raw) To: Eric Abrahamsen; +Cc: emacs-devel > From: Eric Abrahamsen <eric@ericabrahamsen.net> > Date: Sun, 16 Apr 2017 20:45:19 -0700 > > >> (defun nnir-run-query (specs) > >> (let* ((results []) > >> (threads > >> (mapcar > >> (lambda (x) > >> (let* ((server (car x)) > >> (search-engine (nnir-server-to-search-engine server))) > >> (make-thread > >> (lambda () > >> (setq results > >> (vconcat > >> (nnir-run-search > >> search-engine > >> server > >> (cdr (assq 'nnir-query-spec specs)) > >> (cadr x)) > >> results)))))) > >> (cdr (assq 'nnir-group-spec specs))))) > >> (mapc #'thread-join threads) > >> results)) > >> > >> I'm testing with a single IMAP server query (ie, only one thread is > >> being created). The nnir-run-search function for the IMAP backend ends > >> up calling nnimap-send-command--> nnimap-wait-for-response--> > >> nnheader-accept-process-output--> accept-process-output, so I'm > >> expecting that's where the thread yields. In this chain of calls, where's the backend process started? > > error ("Attempt to accept output from process %s locked to thread %s", > > SDATA (proc->name), SDATA (XTHREAD (proc->thread)->name)); > > > > I guess that indicates you might be doing something wrong (though > > obviously Emacs shouldn't be crashing) > > So perhaps an existing process can't be "moved" to another thread? What does it mean "moved" in this context? How did you try to "move" a process to another thread? The ELisp manual says: ... by default a process is locked to the thread that created it. When a process is locked to a thread, output from the process can only be accepted by that thread. If you want to be able to accept process output from a thread other than the one which created it, you need to call set-process-thread. > But the segfault here seems to be coming from a borked attempt to > represent either the process or the thread as a string.... Yes. Should be fixed now. But my advice is to always give your thread meaningful names, as doing so will help you with debugging (unless you are very good in remembering the hex addresses of your thread objects ;-). ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: make-thread with lambda form instead of function symbol 2017-04-17 7:02 ` Eli Zaretskii @ 2017-04-17 16:54 ` Eric Abrahamsen 2017-04-17 17:18 ` Eric Abrahamsen 0 siblings, 1 reply; 17+ messages in thread From: Eric Abrahamsen @ 2017-04-17 16:54 UTC (permalink / raw) To: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: >> From: Eric Abrahamsen <eric@ericabrahamsen.net> >> Date: Sun, 16 Apr 2017 20:45:19 -0700 >> >> >> (defun nnir-run-query (specs) >> >> (let* ((results []) >> >> (threads >> >> (mapcar >> >> (lambda (x) >> >> (let* ((server (car x)) >> >> (search-engine (nnir-server-to-search-engine server))) >> >> (make-thread >> >> (lambda () >> >> (setq results >> >> (vconcat >> >> (nnir-run-search >> >> search-engine >> >> server >> >> (cdr (assq 'nnir-query-spec specs)) >> >> (cadr x)) >> >> results)))))) >> >> (cdr (assq 'nnir-group-spec specs))))) >> >> (mapc #'thread-join threads) >> >> results)) >> >> >> >> I'm testing with a single IMAP server query (ie, only one thread is >> >> being created). The nnir-run-search function for the IMAP backend ends >> >> up calling nnimap-send-command--> nnimap-wait-for-response--> >> >> nnheader-accept-process-output--> accept-process-output, so I'm >> >> expecting that's where the thread yields. > > In this chain of calls, where's the backend process started? > >> > error ("Attempt to accept output from process %s locked to thread %s", >> > SDATA (proc->name), SDATA (XTHREAD (proc->thread)->name)); >> > >> > I guess that indicates you might be doing something wrong (though >> > obviously Emacs shouldn't be crashing) >> >> So perhaps an existing process can't be "moved" to another thread? > > What does it mean "moved" in this context? How did you try to "move" > a process to another thread? > > The ELisp manual says: > > ... by default a process is locked to the thread > that created it. When a process is locked to a thread, output from the > process can only be accepted by that thread. > > If you want to be able to accept process output from a thread other > than the one which created it, you need to call set-process-thread. Okay that certainly explains it -- I hadn't found that part of the manual. The IMAP process in question was long-running, created well before this thread was, so I was doing exactly the wrong thing. (All I meant by "move" was starting the process in one thread, and accepting its output in another.) >> But the segfault here seems to be coming from a borked attempt to >> represent either the process or the thread as a string.... > > Yes. Should be fixed now. But my advice is to always give your > thread meaningful names, as doing so will help you with debugging > (unless you are very good in remembering the hex addresses of your > thread objects ;-). Segfault's gone, thank you. Now to figure out where to stick the call to `set-process-thread'. And thanks for the "thread apply all bt" trick, I'll remember that. Eric ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: make-thread with lambda form instead of function symbol 2017-04-17 16:54 ` Eric Abrahamsen @ 2017-04-17 17:18 ` Eric Abrahamsen 0 siblings, 0 replies; 17+ messages in thread From: Eric Abrahamsen @ 2017-04-17 17:18 UTC (permalink / raw) To: emacs-devel Eric Abrahamsen <eric@ericabrahamsen.net> writes: > Eli Zaretskii <eliz@gnu.org> writes: [...] >> What does it mean "moved" in this context? How did you try to "move" >> a process to another thread? >> >> The ELisp manual says: >> >> ... by default a process is locked to the thread >> that created it. When a process is locked to a thread, output from the >> process can only be accepted by that thread. >> >> If you want to be able to accept process output from a thread other >> than the one which created it, you need to call set-process-thread. > > Okay that certainly explains it -- I hadn't found that part of the > manual. The IMAP process in question was long-running, created well > before this thread was, so I was doing exactly the wrong thing. (All I > meant by "move" was starting the process in one thread, and accepting > its output in another.) > > Segfault's gone, thank you. Now to figure out where to stick the call to > `set-process-thread'. I tried unlocking all IMAP processes early on, when they're first created, and so far it seems to be working great! ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: make-thread with lambda form instead of function symbol 2017-04-17 1:12 ` Eric Abrahamsen 2017-04-17 1:46 ` Noam Postavsky @ 2017-04-17 6:51 ` Eli Zaretskii 2017-04-17 6:59 ` Andrew Cohen 2 siblings, 0 replies; 17+ messages in thread From: Eli Zaretskii @ 2017-04-17 6:51 UTC (permalink / raw) To: Eric Abrahamsen; +Cc: emacs-devel > From: Eric Abrahamsen <eric@ericabrahamsen.net> > Date: Sun, 16 Apr 2017 18:12:17 -0700 > > #0 0x000000000058879c in terminate_due_to_signal (sig=6, backtrace_limit=2147483647) at emacs.c:363 > #1 0x000000000061dbf4 in die (msg=0x74e3fd "STRINGP (a)", file=0x74e330 "lisp.h", line=1276) at alloc.c:7339 > #2 0x0000000000582dfd in XSTRING (a=...) at lisp.h:1276 > #3 0x0000000000582e44 in SDATA (string=...) at lisp.h:1327 > #4 0x000000000069f953 in Faccept_process_output (process=..., seconds=..., millisec=..., just_this_one=...) at process.c:4566 Please try the latest master, I hope I fixed this blunder. In the future, when reporting backtraces from multithreaded Lisp programs, please always say "thread apply all bt", to produce backtraces of all the threads, not just the current one. Otherwise, some important information could be missing. Thanks. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: make-thread with lambda form instead of function symbol 2017-04-17 1:12 ` Eric Abrahamsen 2017-04-17 1:46 ` Noam Postavsky 2017-04-17 6:51 ` Eli Zaretskii @ 2017-04-17 6:59 ` Andrew Cohen 2017-04-17 17:32 ` Eric Abrahamsen 2017-04-20 1:22 ` Eric Abrahamsen 2 siblings, 2 replies; 17+ messages in thread From: Andrew Cohen @ 2017-04-17 6:59 UTC (permalink / raw) To: emacs-devel It would be great to get the searches done concurrently. This is the last serious (IMHO) problem with gnus searches---the searching part can take a long time. The current implementation tries to collect everything to minimize connections to the backends (i.e. searching multiple groups on a single backend should use a single connection) but even imap searching gets to be a pain when several imap servers are involved. Just a side comment: the existing nnir-run-query handles multiple groups with different backends mostly just fine (albeit searching sequentially rather than concurrently). The limitation is that the search query must be common to the different backends (this is the big issue that your general search query language would fix). I (used to) routinely combine gmane, namazu, and imap groups in my searches (used to since I stopped using namazu long ago and gmane search is now defunct :(). And a side-side comment: if the different backends allow different criteria then search groups from different backends will prompt for different criteria for each backend. Cumbersome but occasionally helpful. Andy ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: make-thread with lambda form instead of function symbol 2017-04-17 6:59 ` Andrew Cohen @ 2017-04-17 17:32 ` Eric Abrahamsen 2017-04-18 1:00 ` Andrew Cohen 2017-04-20 1:22 ` Eric Abrahamsen 1 sibling, 1 reply; 17+ messages in thread From: Eric Abrahamsen @ 2017-04-17 17:32 UTC (permalink / raw) To: emacs-devel Andrew Cohen <cohen@bu.edu> writes: > It would be great to get the searches done concurrently. This is the > last serious (IMHO) problem with gnus searches---the searching part can > take a long time. The current implementation tries to collect everything > to minimize connections to the backends (i.e. searching multiple groups > on a single backend should use a single connection) but even imap > searching gets to be a pain when several imap servers are involved. Subjectively, the thread trick seems to really speed things up. I've also been looking at some of the IMAP extensions to improve single-server search -- MULTISEARCH could speed things up significantly, and wouldn't be hard to implement. I'm not sure about SEARCHRES. It doesn't look like it actually saves much time, and would be very hard to integrate with the structure of Gnus searches. > Just a side comment: the existing nnir-run-query handles multiple groups > with different backends mostly just fine (albeit searching sequentially > rather than concurrently). The limitation is that the search query must > be common to the different backends (this is the big issue that your > general search query language would fix). I (used to) routinely combine > gmane, namazu, and imap groups in my searches (used to since I stopped > using namazu long ago and gmane search is now defunct :(). > > And a side-side comment: if the different backends allow different > criteria then search groups from different backends will prompt for > different criteria for each backend. Cumbersome but occasionally > helpful. Actually, in the implementation I'm working on now, I've removed the additional criteria. The general query language makes selecting imap keys unnecessary, the gmane "author" criteria can simply be transformed from the "from" keyword (not to mention that this support is now theoretical!), and all the other backend criteria specify groups: can't we just take that from the group search spec? I'll be happy to re-instate criteria if they really turn out to be necessary, but I'd like to try to do away with them if possible. Eric ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: make-thread with lambda form instead of function symbol 2017-04-17 17:32 ` Eric Abrahamsen @ 2017-04-18 1:00 ` Andrew Cohen 2017-04-18 1:38 ` Eric Abrahamsen 0 siblings, 1 reply; 17+ messages in thread From: Andrew Cohen @ 2017-04-18 1:00 UTC (permalink / raw) To: emacs-devel >>>>> "Eric" == Eric Abrahamsen <eric@ericabrahamsen.net> writes: >> And a side-side comment: if the different backends allow >> different criteria then search groups from different backends >> will prompt for different criteria for each backend. Cumbersome >> but occasionally helpful. Eric> Actually, in the implementation I'm working on now, I've Eric> removed the additional criteria. The general query language Eric> makes selecting imap keys unnecessary, the gmane "author" Eric> criteria can simply be transformed from the "from" keyword Eric> (not to mention that this support is now theoretical!), and Eric> all the other backend criteria specify groups: can't we just Eric> take that from the group search spec? Eliminating the criteria sounds good---it was present just to deal with the non-uniformity of search query formats across different backends, so once the universal language is in place it should go away forever. Best, Andy ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: make-thread with lambda form instead of function symbol 2017-04-18 1:00 ` Andrew Cohen @ 2017-04-18 1:38 ` Eric Abrahamsen 0 siblings, 0 replies; 17+ messages in thread From: Eric Abrahamsen @ 2017-04-18 1:38 UTC (permalink / raw) To: emacs-devel Andrew Cohen <cohen@bu.edu> writes: >>>>>> "Eric" == Eric Abrahamsen <eric@ericabrahamsen.net> writes: > > >> And a side-side comment: if the different backends allow > >> different criteria then search groups from different backends > >> will prompt for different criteria for each backend. Cumbersome > >> but occasionally helpful. > > Eric> Actually, in the implementation I'm working on now, I've > Eric> removed the additional criteria. The general query language > Eric> makes selecting imap keys unnecessary, the gmane "author" > Eric> criteria can simply be transformed from the "from" keyword > Eric> (not to mention that this support is now theoretical!), and > Eric> all the other backend criteria specify groups: can't we just > Eric> take that from the group search spec? > > Eliminating the criteria sounds good---it was present just to deal with > the non-uniformity of search query formats across different backends, > so once the universal language is in place it should go away forever. Excellent, that's good to hear. I'll keep working on this. Oddly, the main slowdown now is simply finding good documentation on the various engines' search syntax. I'll also see if there are any other search engines worth adding. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: make-thread with lambda form instead of function symbol 2017-04-17 6:59 ` Andrew Cohen 2017-04-17 17:32 ` Eric Abrahamsen @ 2017-04-20 1:22 ` Eric Abrahamsen 1 sibling, 0 replies; 17+ messages in thread From: Eric Abrahamsen @ 2017-04-20 1:22 UTC (permalink / raw) To: emacs-devel Andrew Cohen <cohen@bu.edu> writes: > It would be great to get the searches done concurrently. This is the > last serious (IMHO) problem with gnus searches---the searching part can > take a long time. The current implementation tries to collect everything > to minimize connections to the backends (i.e. searching multiple groups > on a single backend should use a single connection) but even imap > searching gets to be a pain when several imap servers are involved. Bah, this isn't quite working. Searching more than one IMAP server causes weird results and/or hangs. Searching other backends, or one IMAP server plus other backends, seems to work okay. I have a hunch that this comes from the way Gnus backends share the nntp-server-buffer variable and swap symbols around -- I think the processes might be stepping on each others' toes from thread to thread. nnimap-wait-for-response loops accept-process-output on a 0.01 second timeout, so I can imagine that two or more threads could be fighting over the meaning of nntp-server-buffer. Anyway, I've gone down enough garden paths here. I'm going to leave things set up for threading, but not actually use threads for now. Once the rest of the stuff is in place there will be time to figure out what's going wrong. Eric ^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2017-04-20 1:22 UTC | newest] Thread overview: 17+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2017-04-16 16:05 make-thread with lambda form instead of function symbol Eric Abrahamsen 2017-04-16 16:21 ` Noam Postavsky 2017-04-16 18:11 ` Eric Abrahamsen 2017-04-16 18:44 ` Noam Postavsky 2017-04-16 20:02 ` Eric Abrahamsen 2017-04-17 1:12 ` Eric Abrahamsen 2017-04-17 1:46 ` Noam Postavsky 2017-04-17 3:45 ` Eric Abrahamsen 2017-04-17 7:02 ` Eli Zaretskii 2017-04-17 16:54 ` Eric Abrahamsen 2017-04-17 17:18 ` Eric Abrahamsen 2017-04-17 6:51 ` Eli Zaretskii 2017-04-17 6:59 ` Andrew Cohen 2017-04-17 17:32 ` Eric Abrahamsen 2017-04-18 1:00 ` Andrew Cohen 2017-04-18 1:38 ` Eric Abrahamsen 2017-04-20 1:22 ` Eric Abrahamsen
Code repositories for project(s) associated with this public inbox https://git.savannah.gnu.org/cgit/emacs.git This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).