changeset 82991:2b26656ff804

MULTI_KBOARD support for ttys. Input-related bugfixes for X+tty sessions. lib-src/emacsclient.c (pty_conversation): Fix errno check for read from fileno(in). src/config.in: Unconditionally define MULTI_KBOARD. src/frame.c (make_terminal_frame): Initialize f->kboard. src/keyboard.c (cmd_error_internal): Don't kill Emacs if a Quit was pressed on the tty of a X+tty session. (read_avail_input): Initialize nread to zero. Abort if there is no tty after a termcap read. (interrupt_signal)[USG]: Always reset signal handler. (init_keyboard): Always set signal handler for SIGINT/SIGQUIT if noninteractive. src/term.c (term_dummy_init): Initialize kboard to the initial_kboard. (term_init): Free component structures of the initial tty. Clear xmalloced structures. Moved rif initialization to syms_of_term. (term_init)[MULTI_KBOARD]: Initialize tty->kboard. (delete_tty)[MULTI_KBOARD]: Delete the keyboard. (syms_of_term): Initialize tty_display_method_template. src/termchar.h (tty_output)[MULTI_KBOARD]: Added kboard member. git-archimport-id: lorentey@elte.hu--2004/emacs--multi-tty--0--patch-31
author Karoly Lorentey <lorentey@elte.hu>
date Fri, 02 Jan 2004 02:54:17 +0000
parents 2ecd1f669db9
children 5de4189e659d
files README.multi-tty lib-src/emacsclient.c src/.gdbinit src/config.in src/frame.c src/frame.h src/keyboard.c src/keyboard.h src/term.c src/termchar.h
diffstat 10 files changed, 213 insertions(+), 120 deletions(-) [+]
line wrap: on
line diff
--- a/README.multi-tty	Fri Jan 02 01:15:26 2004 +0000
+++ b/README.multi-tty	Fri Jan 02 02:54:17 2004 +0000
@@ -6,6 +6,22 @@
 multiple, different tty devices and simultaneous X and tty frames from
 a single Emacs session.
 
+Some use cases:
+
+Emacs is notoriously slow at startup, so most people use another
+editor or emacsclient for quick editing jobs from the console.
+Unfortunately, emacsclient was very awkward to use, because it did not
+support opening a new Emacs frame on the current virtual console.
+Now, with multi-tty support, it can do that.  (Emacsclient starts up
+faster than vi!)
+
+Some Gnus users (including me) run Gnus in an X frame in its own Emacs
+instance, which they typically leave running for weeks.  It would be
+nice if they could connect to this instance from a remote ssh session
+and check their messages without opening a remote X frame or resorting
+to gnus-slave.
+
+
 WHO IS DOING IT
 ---------------
 
@@ -18,46 +34,66 @@
 	tla register-archive lorentey@elte.hu--2004 http://lorentey.web.elte.hu/arch/2004/
 	tla get lorentey@elte.hu--2004/emacs--multi-tty <directory>
 
-(I use tla 1.1.)
+(I use a recent arch development snapshot, but any of the released
+versions of arch will do fine, I think.)
 
+If you don't have arch, the branch has a homepage from which you can
+download conventional patches against Emacs CVS HEAD:
+
+	http://lorentey.web.elte.hu/project/emacs.html
 
 STATUS
 ------
 
-Basic multi-tty support is there; there are some rough edges, but it
-already seems to be usable.  Emacsclient has been extended to support
-opening a new terminal frame.
+Multi-tty support is stable, I think most of the problems were fixed.
+(It still needs testing on other architectures, though.)  Please let
+me know if you find any bugs in it.  Emacsclient has been extended to
+support opening a new terminal frame.
 
-To try it out, compile the multi-tty branch with the following
+To try it out, compile and run the multi-tty branch with the following
 commands:
 
    	mkdir +build
 	cd +build
 	../configure
 	make bootstrap
+	src/emacs -nw
+	M-x server-start
 
-then start up the emacs server (src/emacs -nw, M-x server-start), and
-then (from a shell prompt on another terminal) start emacsclient with
+and then (from a shell prompt on another terminal) start emacsclient
+with
 
-	lib-src/emacsclient -f /optional/file/names...
+	lib-src/emacsclient -t /optional/file/names...
 
 You'll hopefully have two fully working, independent frames on
-separate terminals.  (This seems to be very useful, emacsclient starts
-up even faster than vi!) :-) You can close the newly opened frame and
-return to the shell without exiting Emacs by pressing C-x 5 0, i.e.,
-delete-frame.  Creating new frames on the same tty with C-x 5 2
-works exactly as before.  Suspending Emacs is disabled at the moment.
-If you exit emacs, all terminals should be restored to their previous
-states.
+separate terminals. The new frame is closed automatically when you
+have finished editing the specified files (C-x #), but delete-frame
+(C-x 5 0) also works.  Of course, you can create frames on more than
+two tty devices.
+
+Creating new frames on the same tty with C-x 5 2 works, and they
+behave the same way as in previous Emacs versions.  If you exit emacs,
+all terminals should be restored to their previous states.
+
+This is work in progress, and probably full of bugs.  You should
+always run emacs from gdb, so that you'll have a live instance to
+debug if something goes wrong.  Please send me your reports.
 
-X support is (I hope) working, but at the moment there are problems
-with simultaneous X and tty devices, so don't do that.
+Problems:
+
+	* Suspending Emacs is disabled if there are multiple tty
+	  devices.  Also, there is no way to suspend emacsclient. This
+	  will be fixed.
 
-Mac, Windows and DOS support is broken, probably doesn't even
-compile -- this will be solved later.
+	* X support is (I hope) working, but at the moment there are
+	  problems with simultaneous X and tty devices, so don't do
+	  that - start a separate Emacs with -nw and run the server
+	  there.
 
-Only tested on my GNU/Linux box.
+	* Mac, Windows and DOS support is broken, probably doesn't
+	  even compile -- this will be solved later.
 
+	* Only tested on my GNU/Linux box.
 
 NEWS
 ----
@@ -88,6 +124,78 @@
 
 See arch logs.
 
+THINGS TO DO
+------------
+
+** Fix rif issue with X-tty combo sessions.  IMHO the best thing to do
+   is to get rid of that global variable (and use the value value in
+   display_method, which is guaranteed to be correct).
+
+** Fix faces on tty frames during X-tty combo sessions.
+
+** During an X-tty combo session, a (message "Hello") from a tty frame
+   goes to the X frame.  Fix this.
+
+** Find out the best way to support suspending Emacs with multiple
+   ttys.  My guess: disable it on the controlling tty, but from other
+   ttys pass it on to emacsclient somehow.  (It is (I hope) trivial to
+   extend emacsclient to handle suspend/resume.  A `kill -STOP' almost
+   works right now.)
+
+** Move baud_rate to tty_output.
+
+** Do tty output through term_hooks, like graphical display backends.
+
+** Implement support for starting an interactive Emacs session without
+   an initial frame.  (The user would connect to it and open frames
+   later, with emacsclient.)  Not necessarily a good idea.
+
+** Fix input from raw ttys (again).
+
+** Fix Mac support (I can't do this myself).
+
+** Fix W32 support (I can't do this myself).
+
+** Fix DOS support (I can't do this myself).
+
+** Do a grep on XXX and ?? for more issues.
+
+** Understand Emacs's low-level input system (it seems complicated) :-)
+
+** What does interrupt_input do?  I tried to disable it for raw
+   secondary tty support, but it does not seem to do anything useful.
+   (Update: Look again. X unconditionally enables this, maybe that's
+   why raw terminal support is broken again.  I really do need to
+   understand input.)
+
+** Make sure C-g goes to the right frame.  This is hard, as SIGINT
+   doesn't have a tty parameter. :-(
+
+** I have seen a case when Emacs with multiple ttys fell into a loop
+   eating 100% of CPU time.  Strace showed this loop:
+
+	getpid()                                = 30284
+	kill(30284, SIGIO)                      = 0
+	--- SIGIO (I/O possible) @ 0 (0) ---
+	ioctl(6, FIONREAD, [0])                 = -1 EIO (Input/output error)
+	ioctl(5, FIONREAD, [0])                 = -1 EIO (Input/output error)
+	ioctl(0, FIONREAD, [0])                 = 0
+	sigreturn()                             = ? (mask now [])
+	gettimeofday({1072842297, 747760}, NULL) = 0
+	gettimeofday({1072842297, 747806}, NULL) = 0
+	select(9, [0 3 5 6], NULL, NULL, {0, 0}) = 2 (in [5 6], left {0, 0})
+	select(9, [0 3 5 6], NULL, NULL, {0, 0}) = 2 (in [5 6], left {0, 0})
+	gettimeofday({1072842297, 748245}, NULL) = 0
+
+   I have not been able to reproduce this.
+
+** Define a output_initial value for output_method for the initial
+   frame that is dumped with Emacs.  Checking for this frame (e.g. in
+   cmd_error_internal) is ugly.
+
+** emacsclient -t from an Emacs term buffer does not work, complains
+   about face problems.  This can even lock up Emacs (if the recursive
+   frame sets single_kboard).
 
 DIARY OF CHANGES
 ----------------
@@ -222,7 +330,7 @@
 
    (Done, nothing to do.  It seems that Emacs does not receive SIGHUP
    from secondary ttys, which is actually a good thing.)  (Update: I
-   think it would be a bad idea to remove server-frames anyway.)
+   think it would be a bad idea to remove server-frames.)
 
 -- Change emacsclient/server.el to support the -t argument better,
    i.e. automatically close the socket when the frame is closed.
@@ -316,75 +424,10 @@
    the point of being unusable.  The rif variable causes constant
    core dumps.  Handling input is indeed tricky.)
 
-THINGS TO DO
-------------
-
-** Fix rif issue with X-tty combo sessions.  IMHO the best thing to do
-   is to get rid of that global variable (and use the value value in
-   display_method, which is guaranteed to be correct).
-
-** Fix faces on tty frames during X-tty combo sessions.
-
-** Find out the best way to support suspending Emacs with multiple
-   ttys.  My guess: disable it on the controlling tty, but from other
-   ttys pass it on to emacsclient somehow.  (It is (I hope) trivial to
-   extend emacsclient to handle suspend/resume.  A `kill -STOP' almost
-   works right now.)
-
-** Move baud_rate to tty_output.
-
-** Do tty output through term_hooks, like graphical display backends.
-
-** Implement support for starting an interactive Emacs session without
-   an initial frame.  (The user would connect to it and open frames
-   later, with emacsclient.)  Not necessarily a good idea.
-
-** Fix input from raw ttys (again).
-
-** Fix Mac support (I can't do this myself).
-
-** Fix W32 support (I can't do this myself).
-
-** Fix DOS support (I can't do this myself).
-
-** Do a grep on XXX and ?? for more issues.
+-- Rewrite multi-tty input in terms of MULTI_KBOARD.
 
-** Understand Emacs's low-level input system (it seems complicated)
-   :-) and maybe rewrite multi-tty input in terms of MULTI_KBOARD.
-   (Update: This backtrace from a tty-X combo session hints that this
-   may be necessary.)
-
-	#0  abort () at /home/lorentey/work/emacs/emacs--multi-tty/src/emacs.c:417
-	#1  0x081104fb in read_char (commandflag=0, nmaps=0, maps=0x0, prev_event=675499188, used_mouse_menu=0x0) at /home/lorentey/work/emacs/emacs--multi-tty/src/keyboard.c:2581
-	#2  0x0819f23e in read_filtered_event (no_switch_frame=1, ascii_required=0, error_nonascii=0, input_method=0) at /home/lorentey/work/emacs/emacs--multi-tty/src/lread.c:468
-	#3  0x0819387c in Fy_or_n_p (prompt=1759896324) at /home/lorentey/work/emacs/emacs--multi-tty/src/fns.c:3115
-	...
-
-** What does interrupt_input do?  I tried to disable it for raw
-   secondary tty support, but it does not seem to do anything useful.
-   (Update: Look again. X unconditionally enables this, maybe that's
-   why raw terminal support is broken again.  I really do need to
-   understand input.)
-
-** Make sure C-g goes to the right frame.  This is hard, as SIGINT
-   doesn't have a tty parameter. :-(
-
-** I have seen a case when Emacs with multiple ttys fell into a loop
-   eating 100% of CPU time.  Strace showed this loop:
-
-	getpid()                                = 30284
-	kill(30284, SIGIO)                      = 0
-	--- SIGIO (I/O possible) @ 0 (0) ---
-	ioctl(6, FIONREAD, [0])                 = -1 EIO (Input/output error)
-	ioctl(5, FIONREAD, [0])                 = -1 EIO (Input/output error)
-	ioctl(0, FIONREAD, [0])                 = 0
-	sigreturn()                             = ? (mask now [])
-	gettimeofday({1072842297, 747760}, NULL) = 0
-	gettimeofday({1072842297, 747806}, NULL) = 0
-	select(9, [0 3 5 6], NULL, NULL, {0, 0}) = 2 (in [5 6], left {0, 0})
-	select(9, [0 3 5 6], NULL, NULL, {0, 0}) = 2 (in [5 6], left {0, 0})
-	gettimeofday({1072842297, 748245}, NULL) = 0
-
-   I have not been able to reproduce this.
+   (Done.  In fact, there was no need to rewrite anything, I just
+   added a kboard member to tty_display_info, and initialized the
+   frame's kboard from there.)
 
 ;;; arch-tag: 8da1619e-2e79-41a8-9ac9-a0485daad17d
--- a/lib-src/emacsclient.c	Fri Jan 02 01:15:26 2004 +0000
+++ b/lib-src/emacsclient.c	Fri Jan 02 02:54:17 2004 +0000
@@ -794,7 +794,7 @@
           {
             do {
               res = read (fileno (in), string, BUFSIZ-1);
-            } while (res == EINTR);
+            } while (res < 0 && errno == EINTR);
             if (res < 0)
               {
                 reset_tty ();
--- a/src/.gdbinit	Fri Jan 02 01:15:26 2004 +0000
+++ b/src/.gdbinit	Fri Jan 02 02:54:17 2004 +0000
@@ -383,7 +383,7 @@
 
 show environment DISPLAY
 show environment TERM
-set args -geometry 80x40+0+0
+#set args -geometry 80x40+0+0
 
 # Don't let abort actually run, as it will make
 # stdio stop working and therefore the `pr' command above as well.
--- a/src/config.in	Fri Jan 02 01:15:26 2004 +0000
+++ b/src/config.in	Fri Jan 02 02:54:17 2004 +0000
@@ -863,6 +863,12 @@
 #define HAVE_MOUSE
 #endif
 
+/* Multi-tty support relies on MULTI_KBOARD.  It seems safe to turn it
+   on unconditionally. */
+#ifndef MULTI_KBOARD
+#define MULTI_KBOARD
+#endif
+
 /* Define USER_FULL_NAME to return a string
    that is the user's full name.
    It can assume that the variable `pw'
--- a/src/frame.c	Fri Jan 02 01:15:26 2004 +0000
+++ b/src/frame.c	Fri Jan 02 02:54:17 2004 +0000
@@ -488,6 +488,7 @@
   char name[20];
   
 #ifdef MULTI_KBOARD
+  /* Create the initial keyboard. */
   if (!initial_kboard)
     {
       initial_kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
@@ -567,6 +568,9 @@
       }
     FRAME_TTY (f)->reference_count++;
     f->display_method = FRAME_TTY (f)->display_method;
+#ifdef MULTI_KBOARD
+    f->kboard = FRAME_TTY (f)->kboard;
+#endif
   }
   
 #ifdef CANNOT_DUMP
--- a/src/frame.h	Fri Jan 02 01:15:26 2004 +0000
+++ b/src/frame.h	Fri Jan 02 02:54:17 2004 +0000
@@ -292,8 +292,10 @@
 
 #ifdef MULTI_KBOARD
   /* A pointer to the kboard structure associated with this frame.
-     For termcap frames, this points to initial_kboard.  For X frames,
-     it will be the same as display.x->display_info->kboard.  */
+     For termcap frames, it will be the same as
+     output_data.tty->display_info->kboard.
+     For X frames, it will be the same as
+     output_data.x->display_info->kboard.  */
   struct kboard *kboard;
 #endif
 
--- a/src/keyboard.c	Fri Jan 02 01:15:26 2004 +0000
+++ b/src/keyboard.c	Fri Jan 02 02:54:17 2004 +0000
@@ -1205,7 +1205,8 @@
 	 running under a window system.  */
       || (!NILP (Vwindow_system)
 	  && !inhibit_window_system
-	  && FRAME_TERMCAP_P (sf))
+	  && FRAME_TERMCAP_P (sf)
+          && !FRAME_TTY (sf)->type) /* XXX This is ugly. */
       || noninteractive)
     {
       stream = Qexternal_debugging_output;
@@ -6594,7 +6595,7 @@
 {
   struct input_event buf[KBD_BUFFER_SIZE];
   register int i;
-  int nread;
+  int nread = 0;
   
   for (i = 0; i < KBD_BUFFER_SIZE; i++)
     EVENT_INIT (buf[i]);
@@ -6738,10 +6739,13 @@
 #endif /* not MSDOS */
 #endif /* not WINDOWSNT */
 
+      if (!tty)
+        abort ();
+      
       /* Select frame corresponding to the active tty.  Note that the
          value of selected_frame is not reliable here, redisplay tends
          to temporarily change it.  But tty should always be non-NULL. */
-      frame = (tty ? tty->top_frame : selected_frame);
+      frame = tty->top_frame;
 
       for (i = 0; i < nread; i++)
 	{
@@ -10245,13 +10249,10 @@
   struct frame *sf = SELECTED_FRAME ();
 
 #if defined (USG) && !defined (POSIX_SIGNALS)
-  if (!read_socket_hook && NILP (Vwindow_system))
-    {
-      /* USG systems forget handlers when they are used;
-	 must reestablish each time */
-      signal (SIGINT, interrupt_signal);
-      signal (SIGQUIT, interrupt_signal);
-    }
+  /* USG systems forget handlers when they are used;
+     must reestablish each time */
+  signal (SIGINT, interrupt_signal);
+  signal (SIGQUIT, interrupt_signal);
 #endif /* USG */
 
   cancel_echoing ();
@@ -10626,7 +10627,7 @@
   wipe_kboard (current_kboard);
   init_kboard (current_kboard);
 
-  if (!noninteractive && !read_socket_hook && NILP (Vwindow_system))
+  if (!noninteractive)
     {
       signal (SIGINT, interrupt_signal);
 #if defined (HAVE_TERMIO) || defined (HAVE_TERMIOS)
--- a/src/keyboard.h	Fri Jan 02 01:15:26 2004 +0000
+++ b/src/keyboard.h	Fri Jan 02 02:54:17 2004 +0000
@@ -21,7 +21,7 @@
 /* Length of echobuf field in each KBOARD.  */
 
 /* Each KBOARD represents one logical input stream from which Emacs gets input.
-   If we are using an ordinary terminal, it has one KBOARD object.
+   If we are using ordinary terminals, it has one KBOARD object for each terminal device.
    Usually each X display screen has its own KBOARD,
    but when two of them are on the same X server,
    we assume they share a keyboard and give them one KBOARD in common.
@@ -152,7 +152,7 @@
   };
 
 #ifdef MULTI_KBOARD
-/* Temporarily used before a frame has been opened, and for termcap frames */
+/* Temporarily used before a frame has been opened. */
 extern KBOARD *initial_kboard;
 
 /* In the single-kboard state, this is the kboard
--- a/src/term.c	Fri Jan 02 01:15:26 2004 +0000
+++ b/src/term.c	Fri Jan 02 02:54:17 2004 +0000
@@ -2189,6 +2189,7 @@
   tty_list->output = stdout;
   tty_list->Wcm = (struct cm *) xmalloc (sizeof (struct cm));
   tty_list->display_method = (struct display_method *) xmalloc (sizeof (struct display_method));
+  tty_list->kboard = initial_kboard;
   return tty_list;
 }
 
@@ -2212,6 +2213,15 @@
          the dummy terminal created for the initial frame. */
       if (tty->type)
         return tty;
+
+      /* Free up temporary structures. */
+      if (tty->Wcm)
+        xfree (tty->Wcm);
+      if (tty->display_method)
+        xfree (tty->display_method);
+      if (tty->kboard != initial_kboard)
+        abort ();
+      tty->kboard = 0;
     }
   else
     {
@@ -2221,20 +2231,18 @@
       tty_list = tty;
     }
 
-  if (! tty->Wcm)
-    tty->Wcm = (struct cm *) xmalloc (sizeof (struct cm));
-
-  if (! tty->display_method)
-    tty->display_method = (struct display_method *) xmalloc (sizeof (struct display_method));
+  tty->Wcm = (struct cm *) xmalloc (sizeof (struct cm));
+  Wcm_clear (tty);
+
+  /* Each termcap frame has its own display method. */
+  tty->display_method = (struct display_method *) xmalloc (sizeof (struct display_method));
+  bzero (tty->display_method, sizeof (struct display_method));
 
   /* Initialize the common members in the new display method with our
      predefined template. */
   *tty->display_method = tty_display_method_template;
   f->display_method = tty->display_method;
 
-  /* Termcap-based displays don't support window-based redisplay. */
-  f->display_method->rif = 0;
-
   /* Make sure the frame is live; if an error happens, it must be
      deleted. */
   f->output_method = output_termcap;
@@ -2278,7 +2286,7 @@
   FrameCols (tty) = FRAME_COLS (f);
   tty->specified_window = FRAME_LINES (f);
 
-  f->display_method->delete_in_insert_mode = 1;
+  tty->display_method->delete_in_insert_mode = 1;
 
   UseTabs (tty) = 0;
   FRAME_SCROLL_REGION_OK (f) = 0;
@@ -2509,7 +2517,7 @@
     }
 
 #if 0  /* This is not used anywhere. */
-  f->display_method->min_padding_speed = tgetnum ("pb");
+  tty->display_method->min_padding_speed = tgetnum ("pb");
 #endif
 
   TabWidth (tty) = tgetnum ("tw");
@@ -2723,6 +2731,19 @@
   FRAME_CHAR_INS_DEL_OK (f) = 0;
 #endif
 
+#ifdef MULTI_KBOARD
+  tty->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
+  init_kboard (tty->kboard);
+  tty->kboard->next_kboard = all_kboards;
+  all_kboards = tty->kboard;
+  /* Don't let the initial kboard remain current longer than necessary.
+     That would cause problems if a file loaded on startup tries to
+     prompt in the mini-buffer.  */
+  if (current_kboard == initial_kboard)
+    current_kboard = tty->kboard;
+  tty->kboard->reference_count++;
+#endif
+
   /* Don't do this.  I think termcap may still need the buffer. */
   /* xfree (buffer); */
 
@@ -2735,7 +2756,7 @@
   tty_set_terminal_modes (tty);
 
   return tty;
-#endif /* WINDOWSNT */
+#endif /* not WINDOWSNT */
 }
 
 /* VARARGS 1 */
@@ -2844,6 +2865,13 @@
   if (tty->display_method)
     xfree (tty->display_method);
 
+#ifdef MULTI_KBOARD
+  if (tty->kboard && --tty->kboard->reference_count > 0)
+    abort ();
+  if (tty->kboard)
+    delete_kboard (tty->kboard);
+#endif
+  
   bzero (tty, sizeof (struct tty_display_info));
   xfree (tty);
   deleting_tty = 0;
@@ -2897,9 +2925,13 @@
   defsubr (&Sframe_tty_type);
   defsubr (&Sdelete_tty);
 
-  /* XXX tty_display_method_template initialization will go here. */
-
   Fprovide (intern ("multi-tty"), Qnil);
+
+  /* Initialize the display method template. */
+  
+  /* Termcap-based displays don't support window-based redisplay. */
+  tty_display_method_template.rif = 0;
+
 }
 
 
--- a/src/termchar.h	Fri Jan 02 01:15:26 2004 +0000
+++ b/src/termchar.h	Fri Jan 02 02:54:17 2004 +0000
@@ -182,6 +182,11 @@
   /* This is a copy of struct frame's display_method value; needed for
      freeing up memory when deleting the tty. */
   struct display_method *display_method;
+
+#ifdef MULTI_KBOARD
+  /* The terminal's keyboard object. */
+  struct kboard *kboard;
+#endif  
 };
 
 /* A chain of structures for all tty devices currently in use. */