From 16c290d8c16fb0fdb574c837c6b1badbc655efe2 Mon Sep 17 00:00:00 2001 From: Karoly Lorentey Date: Tue, 30 Dec 2003 19:27:57 +0000 Subject: [PATCH] Major bugfixes and slight enhancements. src/dispextern.h (get_tty_size, tabs_safe_p, init_baud_rate): Update prototypes. src/dispnew.c (window_change_signal): Update call to get_tty_size. src/frame.c (Fmake_terminal_frame): Ditto. src/keyboard.c (Fsuspend_emacs): Ditto. src/sysdep.c: Eliminate tty_outputs, wherever possible. (The exceptions are init_sys_modes and reset_sys_modes, which need access to tty-local parameters). (init_baud_rate): Change tty_output parameter to a simple file descriptor. (narrow_foreground_group, widen_foreground_group): Ditto. (tabs_safe_p, get_tty_size): Ditto. (init_sys_modes): Update narrow_foreground_group invocation. (reset_sys_modes): Update widen_foreground_group invocation. (request_sigio)[!FASYNC && STRIDE]: Fix function signature. src/term.c (delete_tty): Only close output file handle if it is different from input. Re-enable freeing of Wcm. (term_init): Update get_tty_size, tabs_safe_p and init_baud_rate invocations. lib-src/emacsclient.c (here): Renamed to frame. (longopts): Change --here to --frame. The -h short option may be confused with --help. (decode_options, print_help_and_exit): Update to reflect above changes. (main): Ditto. lisp/server.el (server-start): Fix frame-live-p call syntax. (server-process-filter): Handle 'emacsclient -f' without file arguments. Don't return any values to emacsclient when 'emacsclient -f -e'. (server-switch-buffer): Prevent infinite recursion when there are no files to edit. git-archimport-id: lorentey@elte.hu--2004/emacs--multi-tty--0--patch-27 --- README.multi-tty | 44 ++++++++++++++++++++------------ lib-src/emacsclient.c | 22 ++++++++-------- lisp/server.el | 12 +++++---- src/dispextern.h | 6 ++--- src/dispnew.c | 2 +- src/frame.c | 2 +- src/keyboard.c | 4 +-- src/sysdep.c | 58 +++++++++++++++++++++---------------------- src/term.c | 10 +++----- 9 files changed, 85 insertions(+), 75 deletions(-) diff --git a/README.multi-tty b/README.multi-tty index 862a287fb9..2ee943b6ed 100644 --- a/README.multi-tty +++ b/README.multi-tty @@ -39,7 +39,7 @@ commands: then start up the emacs server (src/emacs, M-x server-start), and then (from a shell prompt on another terminal) start emacsclient with - lib-src/emacsclient -h /optional/file/names... + lib-src/emacsclient -f /optional/file/names... You'll hopefully have two fully working, independent frames on separate terminals. (This seems to be very useful, emacsclient starts @@ -213,13 +213,7 @@ DIARY OF CHANGES (Seems to be working OK.) -THINGS TO DO ------------- - -** Understand Emacs's low-level input system. It seems - complicated. :-) - -** Fix mysterious memory corruption error with tty deletion. To +-- Fix mysterious memory corruption error with tty deletion. To trigger it, try the following shell command: while true; do TERM=no-such-terminal-definition emacsclient -h; done @@ -230,17 +224,23 @@ THINGS TO DO Why were these vars collected into a struct before multi-tty support?) - The bug does not seem to happen if the error occurs before terminal - initialization or if I comment out all xfree()s in delete_frame. - Update: yes it does, although it is much rarer. Or maybe it's - another bug. + (Done. Whew. It turned out that the problem had nothing to do + with hypothetical external references to Wcm, or any other + tty_output component; it was simply that delete_tty closed the + filehandles of secondary ttys twice, resulting in fclose doubly + free()ing memory. Utterly trivial matter. I love the C's memory + management, it puts hair on your chest.) + +THINGS TO DO +------------ - Idea: Some of these errors may have been caused by having more - file handles than FD_SETSIZE. +** Understand Emacs's low-level input system (it seems complicated) :-) + and maybe rewrite multi-tty input in terms of MULTIKBOARD. ** Find out why does Emacs abort when it wants to close its controlling tty. Hint: chan_process[] array. Hey, maybe - noninterrupt-IO would work, too? + noninterrupt-IO would work, too? Update: no, there is no process + for stdin/out. ** Support raw secondary terminals. (Note that SIGIO works only on the controlling terminal.) Hint: extend read_input_waiting() for @@ -252,9 +252,21 @@ THINGS TO DO ** Issue with SIGIO: it needs to be disabled during redisplay. See if fcntl() kernel behaviour could be emulated by emacsclient. +** Get rid of the accessor macros in termchar.h, or define macros for + all members. + ** Make parts of struct tty_output accessible from Lisp. The device name and the type is sufficient. +** server.el: There are issues with saving files in buffers of closed + clients. Try editing a file with emacsclient -f, and (without + saving it) do a delete-frame. The frame is closed without + question, and a surprising confirmation prompt appears in another + frame. + +** emacsclient.el, server.el: Handle eval or file open errors when + doing -f. + ** Export delete_tty to the Lisp environment, for emacsclient. ** Make sure C-g goes to the right frame. This is hard, as SIGINT @@ -283,6 +295,6 @@ THINGS TO DO ** Fix DOS support (I can't do this myself). - +** Do a grep on XXX and ?? for more issues. ;;; arch-tag: 8da1619e-2e79-41a8-9ac9-a0485daad17d diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c index 174923e2dc..9f08e4dac3 100644 --- a/lib-src/emacsclient.c +++ b/lib-src/emacsclient.c @@ -118,7 +118,7 @@ int eval = 0; char *display = NULL; /* Nonzero means open a new Emacs frame on the current terminal. */ -int here = 0; +int frame = 0; /* If non-NULL, the name of an editor to fallback to if the server is not running. --alternate-editor. */ @@ -135,7 +135,7 @@ struct option longopts[] = { "eval", no_argument, NULL, 'e' }, { "help", no_argument, NULL, 'H' }, { "version", no_argument, NULL, 'V' }, - { "here", no_argument, NULL, 'h' }, + { "frame", no_argument, NULL, 'f' }, { "alternate-editor", required_argument, NULL, 'a' }, { "socket-name", required_argument, NULL, 's' }, { "display", required_argument, NULL, 'd' }, @@ -153,7 +153,7 @@ decode_options (argc, argv) while (1) { int opt = getopt_long (argc, argv, - "VHnea:s:d:h", longopts, 0); + "VHnea:s:d:f", longopts, 0); if (opt == EOF) break; @@ -192,8 +192,8 @@ decode_options (argc, argv) exit (0); break; - case 'h': - here = 1; + case 'f': + frame = 1; break; case 'H': @@ -207,7 +207,7 @@ decode_options (argc, argv) } } - if (here) { + if (frame) { nowait = 0; display = 0; } @@ -225,7 +225,7 @@ Every FILE can be either just a FILENAME or [+LINE[:COLUMN]] FILENAME.\n\ The following OPTIONS are accepted:\n\ -V, --version Just print a version info and return\n\ -H, --help Print this usage information message\n\ --h, --here Open a new Emacs frame on the current terminal\n\ +-f, --frame Open a new Emacs frame on the current terminal\n\ -n, --no-wait Don't wait for the server to return\n\ -e, --eval Evaluate the FILE arguments as ELisp expressions\n\ -d, --display=DISPLAY Visit the file in the given display\n\ @@ -876,7 +876,7 @@ main (argc, argv) /* Process options. */ decode_options (argc, argv); - if ((argc - optind < 1) && !eval && !here) + if ((argc - optind < 1) && !eval && !frame) { fprintf (stderr, "%s: file name or argument required\n", progname); fprintf (stderr, "Try `%s --help' for more information\n", progname); @@ -1048,7 +1048,7 @@ To start the server in Emacs, type \"M-x server-start\".\n", fprintf (out, " "); } - if (here) + if (frame) { if (! init_signals ()) { @@ -1108,7 +1108,7 @@ To start the server in Emacs, type \"M-x server-start\".\n", } else { - if (!here) + if (!frame) { while ((str = fgets (string, BUFSIZ, stdin))) { @@ -1128,7 +1128,7 @@ To start the server in Emacs, type \"M-x server-start\".\n", return 0; } - if (here) + if (frame) { if (! pty_conversation (out)) { diff --git a/lisp/server.el b/lisp/server.el index 9c841071a9..bf7d4a5d35 100644 --- a/lisp/server.el +++ b/lisp/server.el @@ -271,7 +271,7 @@ Prefix arg means just kill any existing server communications subprocess." (while server-frames (let ((frame (cadar server-frames))) (setq server-frames (cdr server-frames)) - (when frame-live-p frame (delete-frame frame 'force)))) + (when (frame-live-p frame) (delete-frame frame 'force)))) (unless leave-dead (if server-process (server-log (message "Restarting server"))) @@ -314,7 +314,7 @@ PROC is the server process. Format of STRING is \"PATH PATH PATH... \\n\"." (coding-system (and default-enable-multibyte-characters (or file-name-coding-system default-file-name-coding-system))) - client nowait eval + client nowait eval newframe (files nil) (lineno 1) (columnno 0)) @@ -336,6 +336,7 @@ PROC is the server process. Format of STRING is \"PATH PATH PATH... \\n\"." (setq request ""))))) ;; Open a new frame at the client. ARG is the name of the pseudo tty. ((and (equal "-pty" arg) (string-match "\\([^ ]*\\) \\([^ ]*\\) " request)) + (setq newframe t) (let ((pty (server-unquote-arg (match-string 1 request))) (type (server-unquote-arg (match-string 2 request)))) (setq request (substring request (match-end 0))) @@ -364,7 +365,7 @@ PROC is the server process. Format of STRING is \"PATH PATH PATH... \\n\"." (if eval (condition-case err (let ((v (eval (car (read-from-string arg))))) - (when v + (when (and (not newframe v)) (with-temp-buffer (let ((standard-output (current-buffer))) (pp v) @@ -382,7 +383,7 @@ PROC is the server process. Format of STRING is \"PATH PATH PATH... \\n\"." (server-visit-files files client nowait) (run-hooks 'post-command-hook)) ;; CLIENT is now a list (CLIENTNUM BUFFERS...) - (if (null (cdr client)) + (if (and (not newframe) (null (cdr client))) ;; This client is empty; get rid of it immediately. (progn (let ((frame (assq (car client) server-frames))) @@ -607,7 +608,8 @@ Arg NEXT-BUFFER is a suggestion; if it is a live buffer, use it." ;; since we've already effectively done that. (if (null next-buffer) (if server-clients - (server-switch-buffer (nth 1 (car server-clients)) killed-one) + (let ((buffer (nth 1 (car server-clients)))) + (and buffer (server-switch-buffer buffer killed-one))) (unless (or killed-one (window-dedicated-p (selected-window))) (switch-to-buffer (other-buffer)) (message "No server buffers remain to edit"))) diff --git a/src/dispextern.h b/src/dispextern.h index e53f36d4a0..a4864068ed 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -2562,11 +2562,11 @@ extern int x_intersect_rectangles P_ ((XRectangle *, XRectangle *, /* Defined in sysdep.c */ -void get_tty_size P_ ((struct tty_output *, int *, int *)); +void get_tty_size P_ ((int, int *, int *)); void request_sigio P_ ((void)); void unrequest_sigio P_ ((void)); -int tabs_safe_p P_ ((struct tty_output *)); -void init_baud_rate P_ ((struct tty_output *)); +int tabs_safe_p P_ ((int)); +void init_baud_rate P_ ((int)); void init_sigio P_ ((int)); /* Defined in xfaces.c */ diff --git a/src/dispnew.c b/src/dispnew.c index 3cf15deeab..593067eae9 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -5927,7 +5927,7 @@ window_change_signal (signalnum) /* If we don't have an argument, */ if (! tty->term_initted) continue; - get_tty_size (tty, &width, &height); + get_tty_size (fileno (TTY_INPUT (tty)), &width, &height); { Lisp_Object tail, frame; diff --git a/src/frame.c b/src/frame.c index 9a532bfdd2..f26bf9ae9c 100644 --- a/src/frame.c +++ b/src/frame.c @@ -656,7 +656,7 @@ Note that changing the size of one terminal frame automatically affects all. */ { int width, height; - get_tty_size (FRAME_TTY (f), &width, &height); + get_tty_size (fileno (TTY_INPUT (FRAME_TTY (f))), &width, &height); change_frame_size (f, height, width, 0, 0, 0); } diff --git a/src/keyboard.c b/src/keyboard.c index 1bb9564060..c9124f0f59 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -10127,7 +10127,7 @@ On such systems, Emacs starts a subshell instead of suspending. */) call1 (Vrun_hooks, intern ("suspend-hook")); GCPRO1 (stuffstring); - get_tty_size (CURTTY (), &old_width, &old_height); + get_tty_size (fileno (TTY_INPUT (CURTTY ())), &old_width, &old_height); reset_all_sys_modes (); /* sys_suspend can get an error if it tries to fork a subshell and the system resources aren't available for that. */ @@ -10143,7 +10143,7 @@ On such systems, Emacs starts a subshell instead of suspending. */) /* Check if terminal/window size has changed. Note that this is not useful when we are running directly with a window system; but suspend should be disabled in that case. */ - get_tty_size (CURTTY (), &width, &height); + get_tty_size (fileno (TTY_INPUT (CURTTY ())), &width, &height); if (width != old_width || height != old_height) change_frame_size (SELECTED_FRAME (), height, width, 0, 0, 0); diff --git a/src/sysdep.c b/src/sysdep.c index b3a46c77eb..7453be6e3a 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -309,10 +309,13 @@ discard_tty_input () #endif /* not WINDOWSNT */ } + #ifdef SIGTSTP /* Arrange for character C to be read as the next input from - the terminal. */ + the terminal. + XXX What if we have multiple ttys? +*/ void stuff_char (char c) @@ -331,7 +334,7 @@ stuff_char (char c) #endif /* SIGTSTP */ void -init_baud_rate (struct tty_output *tty) +init_baud_rate (int fd) { if (noninteractive) emacs_ospeed = 0; @@ -346,7 +349,7 @@ init_baud_rate (struct tty_output *tty) #ifdef VMS struct sensemode sg; - SYS$QIOW (0, fileno (TTY_INPUT (tty)), IO$_SENSEMODE, &sg, 0, 0, + SYS$QIOW (0, fd, IO$_SENSEMODE, &sg, 0, 0, &sg.class, 12, 0, 0, 0, 0 ); emacs_ospeed = sg.xmit_baud; #else /* not VMS */ @@ -354,7 +357,7 @@ init_baud_rate (struct tty_output *tty) struct termios sg; sg.c_cflag = B9600; - tcgetattr (fileno (TTY_INPUT (tty)), &sg); + tcgetattr (fd, &sg); emacs_ospeed = cfgetospeed (&sg); #if defined (USE_GETOBAUD) && defined (getobaud) /* m88k-motorola-sysv3 needs this (ghazi@noc.rutgers.edu) 9/1/94. */ @@ -367,16 +370,16 @@ init_baud_rate (struct tty_output *tty) sg.c_cflag = B9600; #ifdef HAVE_TCATTR - tcgetattr (fileno (TTY_INPUT (tty)), &sg); + tcgetattr (fd, &sg); #else - ioctl (fileno (TTY_INPUT (tty)), TCGETA, &sg); + ioctl (fd, TCGETA, &sg); #endif emacs_ospeed = sg.c_cflag & CBAUD; #else /* neither VMS nor TERMIOS nor TERMIO */ struct sgttyb sg; sg.sg_ospeed = B9600; - if (ioctl (fileno (TTY_INPUT (tty)), TIOCGETP, &sg) < 0) + if (ioctl (fd, TIOCGETP, &sg) < 0) abort (); emacs_ospeed = sg.sg_ospeed; #endif /* not HAVE_TERMIO */ @@ -392,6 +395,7 @@ init_baud_rate (struct tty_output *tty) baud_rate = 1200; } + /*ARGSUSED*/ void set_exclusive_use (fd) @@ -976,7 +980,7 @@ request_sigio () } void -unrequest_sigio (struct tty_output *tty) +unrequest_sigio () { int off = 0; @@ -1078,23 +1082,23 @@ int inherited_pgroup; group, redirect the TTY to point to our own process group. We need to be in our own process group to receive SIGIO properly. */ void -narrow_foreground_group (struct tty_output *tty) +narrow_foreground_group (int fd) { int me = getpid (); setpgrp (0, inherited_pgroup); /* XXX This only works on the controlling tty. */ if (inherited_pgroup != me) - EMACS_SET_TTY_PGRP (fileno (TTY_INPUT (tty)), &me); + EMACS_SET_TTY_PGRP (fd, &me); setpgrp (0, me); } /* Set the tty to our original foreground group. */ void -widen_foreground_group (struct tty_output *tty) +widen_foreground_group (int fd) { if (inherited_pgroup != getpid ()) - EMACS_SET_TTY_PGRP (fileno (TTY_INPUT (tty)), &inherited_pgroup); + EMACS_SET_TTY_PGRP (fd, &inherited_pgroup); setpgrp (0, inherited_pgroup); } @@ -1289,11 +1293,9 @@ static struct tchars new_tchars = {-1,-1,-1,-1,-1,-1}; void init_all_sys_modes (void) { - struct tty_output *tty = tty_list; - while (tty) { + struct tty_output *tty; + for (tty = tty_list; tty; tty = tty->next) init_sys_modes (tty); - tty = tty->next; - } } void @@ -1358,7 +1360,7 @@ nil means don't delete them until `list-processes' is run. */); #ifdef BSD_PGRPS if (! read_socket_hook && EQ (Vwindow_system, Qnil)) - narrow_foreground_group (tty_out); + narrow_foreground_group (fileno (TTY_INPUT (tty_out))); #endif #ifdef HAVE_WINDOW_SYSTEM @@ -1683,11 +1685,11 @@ nil means don't delete them until `list-processes' is run. */); At the time this is called, init_sys_modes has not been done yet. */ int -tabs_safe_p (struct tty_output *tty) +tabs_safe_p (int fd) { struct emacs_tty etty; - EMACS_GET_TTY (fileno (TTY_INPUT (tty)), &etty); + EMACS_GET_TTY (fd, &etty); return EMACS_TTY_TABS_OK (&etty); } @@ -1696,9 +1698,7 @@ tabs_safe_p (struct tty_output *tty) We store 0 if there's no valid information. */ void -get_tty_size (tty_out, widthp, heightp) - struct tty_output *tty_out; - int *widthp, *heightp; +get_tty_size (int fd, int *widthp, int *heightp) { #ifdef TIOCGWINSZ @@ -1706,7 +1706,7 @@ get_tty_size (tty_out, widthp, heightp) /* BSD-style. */ struct winsize size; - if (ioctl (fileno (TTY_INPUT (tty_out)), TIOCGWINSZ, &size) == -1) + if (ioctl (fd, TIOCGWINSZ, &size) == -1) *widthp = *heightp = 0; else { @@ -1720,7 +1720,7 @@ get_tty_size (tty_out, widthp, heightp) /* SunOS - style. */ struct ttysize size; - if (ioctl (fileno (TTY_INPUT (tty_out)), TIOCGSIZE, &size) == -1) + if (ioctl (fd, TIOCGSIZE, &size) == -1) *widthp = *heightp = 0; else { @@ -1733,7 +1733,7 @@ get_tty_size (tty_out, widthp, heightp) struct sensemode tty; - SYS$QIOW (0, fileno (TTY_INPUT (tty_out)), IO$_SENSEMODE, &tty, 0, 0, + SYS$QIOW (0, fd, IO$_SENSEMODE, &tty, 0, 0, &tty.class, 12, 0, 0, 0, 0); *widthp = tty.scr_wid; *heightp = tty.scr_len; @@ -1793,11 +1793,9 @@ set_window_size (fd, height, width) void reset_all_sys_modes (void) { - struct tty_output *tty = tty_list; - while (tty) { + struct tty_output *tty; + for (tty = tty_list; tty; tty = tty->next) reset_sys_modes (tty); - tty = tty->next; - } } /* Prepare the terminal for closing it; move the cursor to the @@ -1889,7 +1887,7 @@ reset_sys_modes (tty_out) #endif #ifdef BSD_PGRPS - widen_foreground_group (tty_out); + widen_foreground_group (fileno (TTY_INPUT (tty_out))); #endif } diff --git a/src/term.c b/src/term.c index 3b029da0b7..72698ed3b2 100644 --- a/src/term.c +++ b/src/term.c @@ -2403,7 +2403,7 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.", /* Get frame size from system, or else from termcap. */ { int height, width; - get_tty_size (tty, &width, &height); + get_tty_size (fileno (TTY_INPUT (tty)), &width, &height); FrameCols (tty) = width; FrameRows (tty) = height; } @@ -2609,7 +2609,7 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.", && tty->TS_end_standout_mode && !strcmp (tty->TS_standout_mode, tty->TS_end_standout_mode)); - UseTabs (tty) = tabs_safe_p (tty) && TabWidth (tty) == 8; + UseTabs (tty) = tabs_safe_p (fileno (TTY_INPUT (tty))) && TabWidth (tty) == 8; TTY_SCROLL_REGION_OK (tty) = (tty->Wcm->cm_abs @@ -2628,7 +2628,7 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.", TTY_FAST_CLEAR_END_OF_LINE (tty) = tty->TS_clr_line != 0; - init_baud_rate (tty); + init_baud_rate (fileno (TTY_INPUT (tty))); if (read_socket_hook) /* Baudrate is somewhat meaningless in this case */ baud_rate = 9600; @@ -2737,7 +2737,7 @@ delete_tty (struct tty_output *tty) if (tty->input) fclose (tty->input); - if (tty->output) + if (tty->output && tty->output != tty->input) fclose (tty->output); if (tty->termscript) fclose (tty->termscript); @@ -2745,10 +2745,8 @@ delete_tty (struct tty_output *tty) if (tty->old_tty) xfree (tty->old_tty); -#if 0 /* XXX There is a dangling reference somewhere into this. */ if (tty->Wcm) xfree (tty->Wcm); -#endif bzero (tty, sizeof (struct tty_output)); xfree (tty); -- 2.20.1