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
This commit is contained in:
Karoly Lorentey 2004-01-02 02:54:17 +00:00
parent daf0170133
commit 7b00d185eb
10 changed files with 212 additions and 119 deletions

View file

@ -6,6 +6,22 @@ The ultimate goal of this branch is to implement support for opening
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 @@ Retrieving the latest version of the branch:
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.
X support is (I hope) working, but at the moment there are problems
with simultaneous X and tty devices, so don't do that.
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.
Mac, Windows and DOS support is broken, probably doesn't even
compile -- this will be solved later.
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.
Only tested on my GNU/Linux box.
Problems:
* Suspending Emacs is disabled if there are multiple tty
devices. Also, there is no way to suspend emacsclient. This
will be fixed.
* 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.
* 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 @@ CHANGELOG
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 @@ DIARY OF CHANGES
(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 @@ DIARY OF CHANGES
the point of being unusable. The rif variable causes constant
core dumps. Handling input is indeed tricky.)
THINGS TO DO
------------
-- Rewrite multi-tty input in terms of MULTI_KBOARD.
** 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.
** 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

View file

@ -794,7 +794,7 @@ pty_conversation (FILE *in)
{
do {
res = read (fileno (in), string, BUFSIZ-1);
} while (res == EINTR);
} while (res < 0 && errno == EINTR);
if (res < 0)
{
reset_tty ();

View file

@ -383,7 +383,7 @@ set print sevenbit-strings
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.

View file

@ -863,6 +863,12 @@ Boston, MA 02111-1307, USA. */
#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'

View file

@ -488,6 +488,7 @@ make_terminal_frame (tty_name, tty_type)
char name[20];
#ifdef MULTI_KBOARD
/* Create the initial keyboard. */
if (!initial_kboard)
{
initial_kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
@ -567,6 +568,9 @@ make_terminal_frame (tty_name, tty_type)
}
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

View file

@ -292,8 +292,10 @@ struct frame
#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

View file

@ -1205,7 +1205,8 @@ cmd_error_internal (data, context)
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 @@ read_avail_input (expected)
{
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 @@ read_avail_input (expected)
#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 @@ interrupt_signal (signalnum) /* If we don't have an argument, */
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);
}
#endif /* USG */
cancel_echoing ();
@ -10626,7 +10627,7 @@ init_keyboard ()
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)

View file

@ -21,7 +21,7 @@ Boston, MA 02111-1307, USA. */
/* 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 @@ struct kboard
};
#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

View file

@ -2189,6 +2189,7 @@ term_dummy_init (void)
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 @@ term_init (Lisp_Object frame, char *name, char *terminal_type)
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 @@ term_init (Lisp_Object frame, char *name, char *terminal_type)
tty_list = tty;
}
if (! tty->Wcm)
tty->Wcm = (struct cm *) xmalloc (sizeof (struct cm));
Wcm_clear (tty);
if (! tty->display_method)
/* 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 @@ term_init (Lisp_Object frame, char *name, char *terminal_type)
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 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
}
#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 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
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 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
tty_set_terminal_modes (tty);
return tty;
#endif /* WINDOWSNT */
#endif /* not WINDOWSNT */
}
/* VARARGS 1 */
@ -2844,6 +2865,13 @@ delete_tty (struct tty_display_info *tty)
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 @@ The function should accept no arguments. */);
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;
}

View file

@ -182,6 +182,11 @@ struct tty_display_info
/* 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. */