emacsclient -t should not suspend Emacs server
authorPaul Eggert <eggert@cs.ucla.edu>
Fri, 11 Jan 2013 02:40:58 +0000 (18:40 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Fri, 11 Jan 2013 02:40:58 +0000 (18:40 -0800)
* lisp.h, sysdep.c (block_tty_out_signal, unblock_tty_out_signal):
New functions.
* term.c (init_tty): Use them instead of rolling our own code.
* sysdep.c (tcsetpgrp_without_stopping): Likewise.  Here, this
switches from 'signal' to 'pthread_sigmask', which is safer in
multithreaded applications.
* term.c (Fresume_tty): Don't bother dissociating if O_IGNORE_CTTY,
which has already arranged for that.
(dissociate_if_controlling_tty): If setsid fails, fall back on TIOCNOTTY.
This is the main part of the bug fix.

Fixes: debbugs:13387

src/ChangeLog
src/lisp.h
src/sysdep.c
src/term.c

index dd22c53..f0d875b 100644 (file)
@@ -1,3 +1,17 @@
+2013-01-11  Paul Eggert  <eggert@cs.ucla.edu>
+
+       emacsclient -t should not suspend Emacs server (Bug#13387)
+       * lisp.h, sysdep.c (block_tty_out_signal, unblock_tty_out_signal):
+       New functions.
+       * term.c (init_tty): Use them instead of rolling our own code.
+       * sysdep.c (tcsetpgrp_without_stopping): Likewise.  Here, this
+       switches from 'signal' to 'pthread_sigmask', which is safer in
+       multithreaded applications.
+       * term.c (Fresume_tty): Don't bother dissociating if O_IGNORE_CTTY,
+       which has already arranged for that.
+       (dissociate_if_controlling_tty): If setsid fails, fall back on TIOCNOTTY.
+       This is the main part of the bug fix.
+
 2013-01-10  Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> (tiny change)
 
        * gtkutil.c (xg_initialize): Add ifdef HAVE_FREETYPE around
index 8db61d3..3200127 100644 (file)
@@ -3462,6 +3462,8 @@ extern void init_sigio (int);
 extern void sys_subshell (void);
 extern void sys_suspend (void);
 extern void discard_tty_input (void);
+extern void block_tty_out_signal (void);
+extern void unblock_tty_out_signal (void);
 extern void init_sys_modes (struct tty_display_info *);
 extern void reset_sys_modes (struct tty_display_info *);
 extern void init_all_sys_modes (void);
index 049eb85..158d2f7 100644 (file)
@@ -714,6 +714,27 @@ init_foreground_group (void)
   inherited_pgroup = getpid () == pgrp ? 0 : pgrp;
 }
 
+/* Block and unblock SIGTTOU.  */
+
+void
+block_tty_out_signal (void)
+{
+#ifdef SIGTTOU
+  sigset_t blocked;
+  sigemptyset (&blocked);
+  sigaddset (&blocked, SIGTTOU);
+  pthread_sigmask (SIG_BLOCK, &blocked, 0);
+#endif
+}
+
+void
+unblock_tty_out_signal (void)
+{
+#ifdef SIGTTOU
+  pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
+#endif
+}
+
 /* Safely set a controlling terminal FD's process group to PGID.
    If we are not in the foreground already, POSIX requires tcsetpgrp
    to deliver a SIGTTOU signal, which would stop us.  This is an
@@ -725,11 +746,10 @@ static void
 tcsetpgrp_without_stopping (int fd, pid_t pgid)
 {
 #ifdef SIGTTOU
-  signal_handler_t handler;
   block_input ();
-  handler = signal (SIGTTOU, SIG_IGN);
+  block_tty_out_signal ();
   tcsetpgrp (fd, pgid);
-  signal (SIGTTOU, handler);
+  unblock_tty_out_signal ();
   unblock_input ();
 #endif
 }
index d76562b..f66a0bd 100644 (file)
@@ -2423,7 +2423,7 @@ frame's terminal). */)
       if (fd == -1)
         error ("Can not reopen tty device %s: %s", t->display_info.tty->name, strerror (errno));
 
-      if (strcmp (t->display_info.tty->name, DEV_TTY))
+      if (!O_IGNORE_CTTY && strcmp (t->display_info.tty->name, DEV_TTY) != 0)
         dissociate_if_controlling_tty (fd);
 
       t->display_info.tty->output = fdopen (fd, "w+");
@@ -2903,13 +2903,23 @@ set_tty_hooks (struct terminal *terminal)
   terminal->delete_terminal_hook = &delete_tty;
 }
 
-/* Drop the controlling terminal if fd is the same device. */
+/* If FD is the controlling terminal, drop it.  */
 static void
 dissociate_if_controlling_tty (int fd)
 {
-  pid_t pgid = tcgetpgrp (fd); /* If tcgetpgrp succeeds, fd is the ctty. */
-  if (0 <= pgid)
-    setsid ();
+  /* If tcgetpgrp succeeds, fd is the controlling terminal,
+     so dissociate it by invoking setsid.  */
+  if (0 <= tcgetpgrp (fd) && setsid () < 0)
+    {
+#ifdef TIOCNOTTY
+      /* setsid failed, presumably because Emacs is already a process
+        group leader.  Fall back on the obsolescent way to dissociate
+        a controlling tty.  */
+      block_tty_out_signal ();
+      ioctl (fd, TIOCNOTTY, 0);
+      unblock_tty_out_signal ();
+#endif
+    }
 }
 
 /* Create a termcap display on the tty device with the given name and
@@ -3030,14 +3040,9 @@ init_tty (const char *name, const char *terminal_type, int must_succeed)
 
   /* On some systems, tgetent tries to access the controlling
      terminal. */
-  {
-    sigset_t blocked;
-    sigemptyset (&blocked);
-    sigaddset (&blocked, SIGTTOU);
-    pthread_sigmask (SIG_BLOCK, &blocked, 0);
-    status = tgetent (tty->termcap_term_buffer, terminal_type);
-    pthread_sigmask (SIG_UNBLOCK, &blocked, 0);
-  }
+  block_tty_out_signal ();
+  status = tgetent (tty->termcap_term_buffer, terminal_type);
+  unblock_tty_out_signal ();
 
   if (status < 0)
     {