unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* A question regarding sit-for (and while-no-input)
@ 2018-09-06 11:29 João Távora
  2018-09-06 11:59 ` João Távora
  0 siblings, 1 reply; 6+ messages in thread
From: João Távora @ 2018-09-06 11:29 UTC (permalink / raw)
  To: emacs-devel

Hi,

In a couple of my extensions (jsonrpc.el and sly), I am using a
technique for synchronously fetching completion candidates from an
external process while still maintaining high responsiveness to the
user's input.

This is very useful for working with company.el, for example.  If the
user types the first few letters of a completion, the system goes to
work immediately fetching candidates.  If the candidates don't arrive in
time, they are silently discarded.

I am running into a bug in my program, which only happens sometimes and
is hard to reproduce.  I don't know how to fix it.

I hope this simplified snippet from the function jsonrpc-request in
lisp/jsonrpc.el illustrates the problem sufficiently for someone to
provide some hint as to what might be going askew:

   (let ((tag (some-unique-symbol))
         (cancelled nil))
     (catch tag
    ...
      (lambda (...) (unless cancelled (throw tag result-or-error)))
    ...
      (cond (cancel-on-input
             (while (sit-for 30))
             (setq cancelled t)
             `(cancelled ,cancel-on-input-retval))
            (t (while t (accept-process-output nil 30)))))
    ...
   )

'cancel-on-input' is a parameter to jsonrpc-request.  If the caller
provides it as 't', it means he/she wants that call to block as long as
there is no input from the user.  A response from the server before that
happens, which takes the form of a call to anonymous lambda, will also
cause the function to return.

Most of the time, this works flawlessly, as intended.  But the behaviour
I'm witnessing is that (throw tag) sometimes happens after the (catch
tag ...) has been torn down.

What am I missing?? If the catch has been torn down then surely (setq
cancelled t) must have run, right?  Otherwise I would be seeing an error
from sit-for, which I'm not.

Thanks,
João







^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: A question regarding sit-for (and while-no-input)
  2018-09-06 11:29 A question regarding sit-for (and while-no-input) João Távora
@ 2018-09-06 11:59 ` João Távora
  2018-09-06 12:33   ` Stefan Monnier
  0 siblings, 1 reply; 6+ messages in thread
From: João Távora @ 2018-09-06 11:59 UTC (permalink / raw)
  To: emacs-devel

João Távora <joaotavora@gmail.com> writes:

> Hi,
>
> In a couple of my extensions (jsonrpc.el and sly), I am using a
> technique for synchronously fetching completion candidates from an
> external process while still maintaining high responsiveness to the
> user's input.
>
> This is very useful for working with company.el, for example.  If the
> user types the first few letters of a completion, the system goes to
> work immediately fetching candidates.  If the candidates don't arrive in
> time, they are silently discarded.
>
> I am running into a bug in my program, which only happens sometimes and
> is hard to reproduce.  I don't know how to fix it.
>
> I hope this simplified snippet from the function jsonrpc-request in
> lisp/jsonrpc.el illustrates the problem sufficiently for someone to
> provide some hint as to what might be going askew:
>
>    (let ((tag (some-unique-symbol))
>          (cancelled nil))
>      (catch tag
>     ...
>       (lambda (...) (unless cancelled (throw tag result-or-error)))
>     ...
>       (cond (cancel-on-input
>              (while (sit-for 30))
>              (setq cancelled t)
>              `(cancelled ,cancel-on-input-retval))
>             (t (while t (accept-process-output nil 30)))))
>     ...
>    )
>
> 'cancel-on-input' is a parameter to jsonrpc-request.  If the caller
> provides it as 't', it means he/she wants that call to block as long as
> there is no input from the user.  A response from the server before that
> happens, which takes the form of a call to anonymous lambda, will also
> cause the function to return.
>
> Most of the time, this works flawlessly, as intended.  But the behaviour
> I'm witnessing is that (throw tag) sometimes happens after the (catch
> tag ...) has been torn down.
>
> What am I missing?? If the catch has been torn down then surely (setq
> cancelled t) must have run, right?  Otherwise I would be seeing an error
> from sit-for, which I'm not.
>
> Thanks,
> João

A quick followup to my question.  I did some more tests and it seems an
using unwind-protect fixes the issue.

   (unwind-protect
     (while (sit-for 30))
    (setq cancelled t)
    ...)

Without it, it seems multiple "sit-for" are entered without ever exiting
properly (properly = "executing through the (setq cancelled t)
instruction").  With it, every sit-for has a corresponding proper exit.

I don't understand the need for the "unwind-protect" and my question
stands.  Is the sit-for call silently quitting or what?  I don't see any
"Quit" in my *Messages* buffer and I'm not pressing C-g at any moment.
I bore down a little bit to keyboard.c's read_char() and it does have
some mentions of quitting, but I honestly don't know if I'm reading it
correctly...

João



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: A question regarding sit-for (and while-no-input)
  2018-09-06 11:59 ` João Távora
@ 2018-09-06 12:33   ` Stefan Monnier
  2018-10-04 16:33     ` João Távora
  0 siblings, 1 reply; 6+ messages in thread
From: Stefan Monnier @ 2018-09-06 12:33 UTC (permalink / raw)
  To: emacs-devel

> A quick followup to my question.  I did some more tests and it seems an
> using unwind-protect fixes the issue.
>
>    (unwind-protect
>      (while (sit-for 30))
>     (setq cancelled t)
>     ...)

Ha, that's exactly what I was about to suggest.

> I don't understand the need for the "unwind-protect" and my question
> stands.  Is the sit-for call silently quitting or what?  I don't see any
> "Quit" in my *Messages* buffer and I'm not pressing C-g at any moment.

Maybe the code is sometimes run within a while-no-input?
Also the sit-for could exit non-locally if some other code
(timer/processfilter) does a `throw`.


        Stefan




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: A question regarding sit-for (and while-no-input)
  2018-09-06 12:33   ` Stefan Monnier
@ 2018-10-04 16:33     ` João Távora
  2018-10-05 12:36       ` Stefan Monnier
  0 siblings, 1 reply; 6+ messages in thread
From: João Távora @ 2018-10-04 16:33 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> A quick followup to my question.  I did some more tests and it seems an
>> using unwind-protect fixes the issue.
>>
>>    (unwind-protect
>>      (while (sit-for 30))
>>     (setq cancelled t)
>>     ...)
>
> Ha, that's exactly what I was about to suggest.

Hi again Stefan & the gang,

After a month-long delay, I am back with another question around this
issue.

I recently changed the code to use while-no-input +
accept-process-output instead of sit-for, because the latter would
sometimes hang in combination with company, company-quickhelp, and C-g.
(but it's very difficult to reproduce).

Anyway everything was going fine until I noticed an unexpected slowdown.
I made a little timing macro.

  (defmacro joaot/time (&rest body)
    `(let ((start (current-time)))
       (prog1
           (progn ,@body)
         (let ((msg (format "Took %s seconds"
                            (format-time-string
                             "%S.%3N"
                             (time-subtract (current-time) start)))))
           (if current-prefix-arg
               (insert " ; " msg " and returned ")
             (message msg))))))

These are the results of pressing C-u C-x C-e SPC in quick succession
after each expression.

   (joaot/time
    (while-no-input
      (while t (accept-process-output nil 0.1)))) ; Took 00.201 seconds and returned t
    
   (joaot/time
    (while-no-input
      (while t (accept-process-output nil 30)))) ; Took 03.822 seconds and returned t 
    
   (joaot/time
    (while (sit-for 30))) ; Took 00.126 seconds and returned nil 
    
   (joaot/time
    (while (sit-for 0.1))) ; Took 00.126 seconds and returned nil

I've switched to the first alternative, since it seems to solve the
problem.  I can't explain the long delay on the second one.  Can
someone?

Thanks,
João














^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: A question regarding sit-for (and while-no-input)
  2018-10-04 16:33     ` João Távora
@ 2018-10-05 12:36       ` Stefan Monnier
  2018-10-06 10:35         ` João Távora
  0 siblings, 1 reply; 6+ messages in thread
From: Stefan Monnier @ 2018-10-05 12:36 UTC (permalink / raw)
  To: emacs-devel

> These are the results of pressing C-u C-x C-e SPC in quick succession
> after each expression.
>
>    (joaot/time
>     (while-no-input
>       (while t (accept-process-output nil 0.1)))) ; Took 00.201 seconds and returned t
>     
>    (joaot/time
>     (while-no-input
>       (while t (accept-process-output nil 30)))) ; Took 03.822 seconds and returned t 

I don't know why this happens to you, but FWIW, I can't reproduce
it here (using Debian).


        Stefan




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: A question regarding sit-for (and while-no-input)
  2018-10-05 12:36       ` Stefan Monnier
@ 2018-10-06 10:35         ` João Távora
  0 siblings, 0 replies; 6+ messages in thread
From: João Távora @ 2018-10-06 10:35 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> These are the results of pressing C-u C-x C-e SPC in quick succession
>> after each expression.
>>
>>    (joaot/time
>>     (while-no-input
>>       (while t (accept-process-output nil 0.1)))) ; Took 00.201 seconds and returned t
>>     
>>    (joaot/time
>>     (while-no-input
>>       (while t (accept-process-output nil 30)))) ; Took 03.822 seconds and returned t 
>
> I don't know why this happens to you, but FWIW, I can't reproduce
> it here (using Debian).

Right....  At first I was going to add it happens just on Windows, but
then I tested it on my Ubuntu virtual server and I get the same result.
But after you reported Debian being fine I tested again at home and
indeed I can't reproduce too.

So, reproducible on Windows (Emacs master) + Ubuntu (Emacs 25).  No
problem on Debian (Emacs master).  Going to try a few more combinations,
but, in the meantime, what can be happening here and how can I debug it?

Thanks,
João



^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2018-10-06 10:35 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-09-06 11:29 A question regarding sit-for (and while-no-input) João Távora
2018-09-06 11:59 ` João Távora
2018-09-06 12:33   ` Stefan Monnier
2018-10-04 16:33     ` João Távora
2018-10-05 12:36       ` Stefan Monnier
2018-10-06 10:35         ` João Távora

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).