Subject: RE: Brainstorming a fix for CTRL-C handling in an emacs shell buf fer (non-TTY)
From: Troy Noble <[email-masked]>
To: "[email-masked]'" <[email-masked]>
Cc: "[email-masked]'" <[email-masked]>
Date: Sun, 6 May 2001 22:16:38 -0600

Christopher,

Looks like t->getpgid() is OK,  it's the

   t->getpgid () != myself->pid

that's causing the behavior... and I think I understand why
now.  Thanks for leading me in the right direction.

What do you think about the patch below for exceptions.cc
instead?  No extra environment variables required this time ;->

Note that I also determined that FSF Emacs users SHOULD NOT use
CYGWIN=tty if they plan to run inside a shell buffer.  Otherwise
the CTRL-C handler doesn't get setup or invoked properly for
reasons I probably don't need to elaborate on.

This likely explains why some folks have reported not being able
to kill other non-cygwin child processes (like java.exe for example)
when running bash in a shell buffer.  They probably had CYGWIN=tty
set.  You probably already knew that, I thought I'd just pass it
along for others who might be having that same problem.

--- exceptions.cc-orig	Fri May  4 23:07:20 2001
+++ exceptions.cc	Sun May  6 21:47:03 2001
@@ -11,6 +11,7 @@
 #include "winsup.h"
 #include <imagehlp.h>
 #include <errno.h>
+#include <unistd.h>
 
 #include "exceptions.h"
 #include "sync.h"
@@ -904,8 +905,21 @@
   tty_min *t = cygwin_shared->tty.get_tty (myself->ctty);
   /* Ignore this if we're not the process group lead since it should be
handled
      *by* the process group leader. */
-  if (t->getpgid () && (t->getpgid () != myself->pid ||
-      (GetTickCount () - t->last_ctrl_c) < MIN_CTRL_C_SLOP))
+    /* Note: t->getpgid() does not correctly reflect the pid of the process
+       group leader when stdin is a pipe (when isatty(0) == 0).
+       So when a native Win32 program like NT Emacs opens a pipe and
supplies
+       that as stdin for a cygwin process, this handler should respond to
the
+       CTRL-C when pid == pgid rather than when pid == t->getpgid().
+       Inside a console window or cygwin-aware XEmacs or rxvt for example,
+       isatty(0) == 1 so the proper behavior is to kill the process whose
+       pid == t->getpgid().
+       NT Emacs users should never set "tty" in their CYGWIN environment
+       variable if they plan to run bash in an Emacs buffer.
+       */
+  if (t->getpgid() &&
+      ((!isatty(0) && myself->pid != myself->pgid) ||
+       (isatty(0) && (t->getpgid () != myself->pid)) ||
+       ((GetTickCount () - t->last_ctrl_c) < MIN_CTRL_C_SLOP)))
     return TRUE;
   else
     /* Otherwise we just send a SIGINT to the process group and return TRUE
(to indicate

Just as Andrew Innes said in

    http://sources.redhat.com/ml/cygwin/2001-01/msg00928.html

FSF Emacs 20.7.1 opens a pipe and passes the read end to the
bash child process as its stdin.  I read through the code just
to see what it was doing so I could understand what was going on.

Back on the cygwin side...

In dtable::init_std_file_from_handle at line 202 I see:

      else if (GetFileType (handle) == FILE_TYPE_PIPE)

Through a long sequence of steps, the end result is
that the array of fds gets initialized in such a way that
isatty(0) always returns 0.  Therefore the code that switches
the tty's PGID when a child forks never kicks in.

I should add... I see this as a GOOD thing that you would not
want to change, otherwise you'd never be able to kill the process
leader for a set of commands in a pipe.

So the simplest solution seems to be to change the ctrl_c_handler
per the above patch.

I too wrote a simple win32 program that emulated the behavior
of NT Emacs's method of pipe/stdin handling.  And was able
to reproduce it quite easily.  I can send the sources along if
you'd like... so you wouldn't have to download/install FSF Emacs
if you didn't want to ;->

An interesting way to reproduce all of this without
running FSF Emacs or even writing a test program:
1. put the following code in the exceptions.cc:ctrl_c_handler
     printf("isatty(0)=%d t->getpgid()=%d myself->pid=%d pgid=%d ppid=%d
progname=%s\n",
	isatty(0), t->getpgid(), myself->pid, myself->pgid, myself->ppid,
myself->progname);
2. start up a bash shell in a console window.
3. create a file /tmp/tmp.sh that looks like:
      sleep 10
4. run bash </tmp/tmp.sh    (this ensures stdin is a pipe)
5. press CTRL-C and you'll see something like:

     isatty(0)=0 t->getpgid()=608 myself->pid=112 pgid=608 ppid=608
         progname=c:\cygwin\bin\sleep.exe
     isatty(0)=0 t->getpgid()=608 myself->pid=608 pgid=608 ppid=1468
         progname=c:\cygwin\bin\bash.exe
     isatty(0)=0 t->getpgid()=608 myself->pid=1468 pgid=1468 ppid=1
         progname=C:\cygwin\bin\bash.exe

Notice that the child shell (pid=608) is the pgid...
rather than the child sleep process (pid=112).

Sorry for the long post.  Hope this solves it once and for
all.  I'm still willing to pursue further if you don't think
this is the right approach yet.

Thanks again for your help, Troy

-----Original Message-----
From: Christopher Faylor [mailto:[email-masked]]
Sent: Saturday, May 05, 2001 2:25 PM
To: [email-masked]'
Subject: Re: Brainstorming a fix for CTRL-C handling in an emacs shell
buf fer (non-TTY)

On Sat, May 05, 2001 at 02:19:24PM -0600, Troy Noble wrote:
>So where would you recommend we go from here?
>
>Maybe looking into the TTY code, and figuring out why it doesn't
>like the way Emacs is opening the pipe to stdin on cygwin processes?

Look at the ctrl_c_handler code and tell me why the test for t->getpgid()
being nonzero is inadequate.

I actually wrote a program to test this and it works fine for me.

I'm not going to download Xemacs, however.  I've heard that it
is unstable...

cgf

--
Want to unsubscribe from this list?
Check out: http://cygwin.com/ml/#unsubscribe-simple

--
Want to unsubscribe from this list?
Check out: http://cygwin.com/ml/#unsubscribe-simple