unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* wait_reading_process_output bug [Was RE: A question on wait_reading_process_output]
@ 2008-05-29 11:30 Herbert Euler
  0 siblings, 0 replies; only message in thread
From: Herbert Euler @ 2008-05-29 11:30 UTC (permalink / raw)
  To: emacs-devel; +Cc: herberteuler

[-- Attachment #1: Type: text/plain, Size: 5855 bytes --]


I think I can reproduce the problem now.  Following the steps I will
introduce later, I see the problem, just as my guess.

I have attatched two files: x.c and x.el.  In the file x.c, the key
logic is very simple, as listed below:

  signal (SIGTERM, handle_interrupt);
  while (keep_looping)
    ;
  printf ("hello, world\n");

We will run this program inside Emacs and send a SIGTERM signal to its
process with "kill PID" at a proper point.  That will make some output
available from the program and change its status to exit, so the code
of the body of the if will be executed, to reproduce the error.

The logic of x.el is also simple:

  (let* ((buf (get-buffer-create "*test*"))
         (proc (start-process "test" buf "/tmp/x")))
    (when (accept-process-output proc 100 nil t)
      (switch-to-buffer buf)))

"/tmp/x" here is the executable file, we will run it as an
asynchronous process, and try to read its output.  We will not read
output from any other processes at the same time, as specified by the
last argument of the calling to `accept-process-output'.  If
`accept-process-output' returns non-nil value, which means it reads
some output from the process according to its docstring, we will
switch to its output buffer.  Otherwise, we stay at the buffer where
we were.

Now I will introduce how to reproduce the bug.

1. Copy the two files, x.el and x.c to /tmp.  Compile x.c:

     herbert@euler:/tmp$ pwd
     /tmp
     herbert@euler:/tmp$ cc -o x x.c
     herbert@euler:/tmp$ ls x*
     x  x.c  x.el
     herbert@euler:/tmp$

2. Start Emacs in gdb:

     (gdb) r -Q /tmp/x.el

Goto the end of the file and type C-x C-e to evaluate the let* form.
In another shell, kill the asynchronous process:

     herbert@euler:/tmp$ ps aux | grep /tmp/x$ | grep -v grep | awk '{ print $2 }'
     690
     herbert@euler:/tmp$ kill 690
     herbert@euler:/tmp$

The argument to kill is the process ID.  The current buffer becomes
*test*.  This is expected: `accept-process-output' returns non-nil, so
the current buffer is switched.

Now quit from Emacs by typing C-x C-c.

3. This time we will set a breakpoint at Faccept_process_output, so
that we can kill the asynchronous process at a proper point:

     (gdb) b Faccept_process_output
     Breakpoint 3 at 0x8253386: file process.c, line 3907.
     (gdb)

And start Emacs in the same way:

     (gdb) r -Q /tmp/x.el

4. Evaluate the let* form in x.el, gdb will take over the control.
Now set a breakpoint at process.c:4458, and continue the execution to
that point:

     Breakpoint 3, Faccept_process_output (process=143107140, seconds=800, millisec=138480921, just_this_one=138480969)
         at process.c:3907
     3907      int secs, usecs = 0;
     (gdb) b process.c:4458
     Breakpoint 4 at 0x8254347: file process.c, line 4458.
     (gdb) c
     Continuing.

     Breakpoint 4, wait_reading_process_output (time_limit=100, microsecs=0, read_kbd=0, do_display=0,
         wait_for_cell=138480921, wait_proc=0x887a440, just_wait_proc=1) at process.c:4458
     4458          if (wait_proc && wait_proc->raw_status_new)
     (gdb)

5. Kill the asynchronous process again.  This will trigger the
condition reproducing the bug.  In another shell, execute the
following commands:

     herbert@euler:/tmp$ ps aux | grep /tmp/x$ | grep -v grep | awk '{ print $2 }'
     5727
     herbert@euler:/tmp$ kill 5727
     herbert@euler:/tmp$

And, after killing the process, in the gdb shell, set another
breakpoint and continue the execution to that point:

     (gdb) b process.c:4472
     Breakpoint 5 at 0x8254591: file process.c, line 4472.
     (gdb) c
     Continuing.

     Breakpoint 5, wait_reading_process_output (time_limit=100, microsecs=0, read_kbd=0,
         do_display=0, wait_for_cell=138481385, wait_proc=0x853a788, just_wait_proc=1)
         at process.c:4472
     4472                  nread = read_process_output (proc, wait_proc->infd);
     (gdb)

The value of nread will be greater than 0, which means something has
been read from wait_proc's output:

     (gdb) c
     Continuing.

     Breakpoint 5, wait_reading_process_output (time_limit=100, microsecs=0, read_kbd=0,
         do_display=0, wait_for_cell=138481385, wait_proc=0x853a788, just_wait_proc=1)
         at process.c:4472
     4472                  nread = read_process_output (proc, wait_proc->infd);
     (gdb) n
     4474                  if (nread == 0)
     (gdb) p nread
     $1 = 13
     (gdb)

wait_reading_process_output promises returning non-null value in such
a case.  But the fact is not as described.  Type finish in the gdb
shell to see this:

     (gdb) finish
     Run till exit from #0  wait_reading_process_output (time_limit=100, microsecs=0, read_kbd=0,
         do_display=0, wait_for_cell=138481385, wait_proc=0x853a788, just_wait_proc=1)
         at process.c:4472
     0x0825375e in Faccept_process_output (process=139700108, seconds=800, millisec=138481385,
         just_this_one=138481433) at process.c:3946
     3946      return
     Value returned is $2 = 0
     (gdb)

This $2 (0) becomes the value of evaluating accept-process-output.
Now delete all of the breakpoints and go back to the Emacs process:

     (gdb) d
     Delete all breakpoints? (y or n) y
     (gdb) c
     Continuing.

The current buffer remains #, not *test*.  The behavior
here is not the same as said in step 2, and is not expected.  Because
accept-process-output has read something, it should return a non-nil
value.  But it does not.

Regards,
Guanpeng Xu


Btw, when I verify the steps to reproduce the bug, I find the
possibility it happens is not very small.  I see the unexpected
behavior at least once without the helping of gdb.
_________________________________________________________________
Discover the new Windows Vista
http://search.msn.com/results.aspx?q=windows+vista&mkt=en-US&form=QBRE

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: x.c --]
[-- Type: text/x-csrc, Size: 407 bytes --]

#include <stdio.h>
#include <signal.h>


int keep_looping = 1;


void
handle_interrupt (int sig)
{
  keep_looping = 0;
}


/* After starting this program, run

     ps aux | grep /tmp/x$ | grep -v grep | awk '{ print $2 }'

   to get the process ID of it.  */

int
main (int argc, char *argv[])
{
  signal (SIGTERM, handle_interrupt);
  while (keep_looping)
    ;
  printf ("hello, world\n");
  return 0;
}

[-- Attachment #3: x.el --]
[-- Type: text/plain, Size: 268 bytes --]

;; Set breakpoints to these places:
;;
;;   Faccept_process_output, process.c:4458, process.c:4472

(let* ((buf (get-buffer-create "*test*"))
       (proc (start-process "test" buf "/tmp/x")))
  (when (accept-process-output proc 100 nil t)
    (switch-to-buffer buf)))

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2008-05-29 11:30 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-05-29 11:30 wait_reading_process_output bug [Was RE: A question on wait_reading_process_output] Herbert Euler

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