]> code.delx.au - gnu-emacs/commitdiff
Delete the gdb-inferior pty when the gdb process exits.
authorChong Yidong <cyd@gnu.org>
Thu, 19 Apr 2012 08:09:30 +0000 (16:09 +0800)
committerChong Yidong <cyd@gnu.org>
Thu, 19 Apr 2012 08:09:30 +0000 (16:09 +0800)
* lisp/progmodes/gdb-mi.el (gdb-inferior-io--maybe-delete-pty): New
function to call delete-process on the gdb-inferior buffer's pty.
(gdb-reset): Use it, instead of relying on kill-buffer to kill the
pty process.
(gdb-update): New arg to suppress talking to the gdb process.
(gdb-done-or-error): Use it.
(gdb-stopped-functions): Rename from gdb-stopped-hooks.
(gdb): Call gdb-inferior-io--maybe-delete-pty as a workaround for
sentinel not being called.

* lisp/comint.el (make-comint-in-buffer, comint-exec): Doc fix.

Fixes: debbugs:11273
lisp/ChangeLog
lisp/comint.el
lisp/progmodes/gdb-mi.el

index 7ef7628b6d6c4cfc3fa3bceb347b1961e8f2aa51..1ce5e7fceeacb128dfe30698907ecb14d4fd0905 100644 (file)
@@ -1,3 +1,17 @@
+2012-04-19  Chong Yidong  <cyd@gnu.org>
+
+       * progmodes/gdb-mi.el (gdb-inferior-io--maybe-delete-pty): New
+       function to call delete-process on the gdb-inferior buffer's pty.
+       (gdb-reset): Use it, instead of relying on kill-buffer to kill the
+       pty process (Bug#11273).
+       (gdb-update): New arg to suppress talking to the gdb process.
+       (gdb-done-or-error): Use it.
+       (gdb-stopped-functions): Rename from gdb-stopped-hooks.
+       (gdb): Call gdb-inferior-io--maybe-delete-pty as a workaround for
+       sentinel not being called.
+
+       * comint.el (make-comint-in-buffer, comint-exec): Doc fix.
+
 2012-04-18  Chong Yidong  <cyd@gnu.org>
 
        * progmodes/grep.el (grep, rgrep): Doc fix (Bug#11268).
index 68fedeb88a9de7c8b9c404a2d7284e6c06a542d2..1098167597154c85fcc663f53e62ad18352f936c 100644 (file)
@@ -699,16 +699,21 @@ BUFFER can be either a buffer or the name of one."
 (defun make-comint-in-buffer (name buffer program &optional startfile &rest switches)
   "Make a Comint process NAME in BUFFER, running PROGRAM.
 If BUFFER is nil, it defaults to NAME surrounded by `*'s.
-PROGRAM should be either a string denoting an executable program to create
-via `start-file-process', or a cons pair of the form (HOST . SERVICE) denoting
-a TCP connection to be opened via `open-network-stream'.  If there is already
-a running process in that buffer, it is not restarted.  Optional fourth arg
-STARTFILE is the name of a file, whose contents are sent to the
-process as its initial input.
+If there is a running process in BUFFER, it is not restarted.
+
+PROGRAM should be one of the following:
+- a string, denoting an executable program to create via
+  `start-file-process'
+- a cons pair of the form (HOST . SERVICE), denoting a TCP
+  connection to be opened via `open-network-stream'
+- nil, denoting a newly-allocated pty.
+
+Optional fourth arg STARTFILE is the name of a file, whose
+contents are sent to the process as its initial input.
 
 If PROGRAM is a string, any more args are arguments to PROGRAM.
 
-Returns the (possibly newly created) process buffer."
+Return the (possibly newly created) process buffer."
   (or (fboundp 'start-file-process)
       (error "Multi-processing is not supported for this system"))
   (setq buffer (get-buffer-create (or buffer (concat "*" name "*"))))
@@ -752,9 +757,18 @@ See `make-comint' and `comint-exec'."
 (defun comint-exec (buffer name command startfile switches)
   "Start up a process named NAME in buffer BUFFER for Comint modes.
 Runs the given COMMAND with SWITCHES, and initial input from STARTFILE.
-Blasts any old process running in the buffer.  Doesn't set the buffer mode.
-You can use this to cheaply run a series of processes in the same Comint
-buffer.  The hook `comint-exec-hook' is run after each exec."
+
+COMMAND should be one of the following:
+- a string, denoting an executable program to create via
+  `start-file-process'
+- a cons pair of the form (HOST . SERVICE), denoting a TCP
+  connection to be opened via `open-network-stream'
+- nil, denoting a newly-allocated pty.
+
+This function blasts any old process running in the buffer, and
+does not set the buffer mode.  You can use this to cheaply run a
+series of processes in the same Comint buffer.  The hook
+`comint-exec-hook' is run after each exec."
   (with-current-buffer buffer
     (let ((proc (get-buffer-process buffer)))  ; Blast any old process.
       (if proc (delete-process proc)))
index 89450cd22766744ed50a45d9a2d8f0a13bebfc17..450075fde42d58c09f98ffc3a04025091c9b02b6 100644 (file)
@@ -375,9 +375,8 @@ Emacs always switches to the thread which caused the stop."
   :version "23.2"
   :link '(info-link "(gdb)GDB/MI Async Records"))
 
-(defcustom gdb-stopped-hooks nil
-  "This variable holds a list of functions to be called whenever
-GDB stops.
+(defcustom gdb-stopped-functions nil
+  "List of functions called whenever GDB stops.
 
 Each function takes one argument, a parsed MI response, which
 contains fields of corresponding MI *stopped async record:
@@ -818,6 +817,11 @@ detailed description of this mode.
             nil 'local)
   (local-set-key "\C-i" 'completion-at-point)
 
+  ;; FIXME: Under some circumstances, `gud-sentinel' apparently does
+  ;; not get called when the gdb process is killed (Bug#11273).
+  (add-hook 'post-command-hook 'gdb-inferior-io--maybe-delete-pty
+           nil t)
+
   (setq gdb-first-prompt t)
   (setq gud-running nil)
 
@@ -1510,6 +1514,14 @@ DOC is an optional documentation string."
   (gdb-display-buffer
    (gdb-get-buffer-create 'gdb-inferior-io) t))
 
+(defun gdb-inferior-io--maybe-delete-pty ()
+  (let ((proc (get-buffer-process gud-comint-buffer))
+       (inf-pty (get-process "gdb-inferior")))
+    (and (or (null proc)
+            (memq (process-status proc) '(exit signal)))
+        inf-pty
+        (delete-process inf-pty))))
+
 (defconst gdb-frame-parameters
   '((height . 14) (width . 80)
     (unsplittable . t)
@@ -1746,24 +1758,27 @@ If `gdb-thread-number' is nil, just wrap NAME in asterisks."
   (setq gdb-output-sink 'user)
   (setq gdb-pending-triggers nil))
 
-(defun gdb-update ()
-  "Update buffers showing status of debug session."
+(defun gdb-update (&optional no-proc)
+  "Update buffers showing status of debug session.
+If NO-PROC is non-nil, do not try to contact the GDB process."
   (when gdb-first-prompt
     (gdb-force-mode-line-update
      (propertize "initializing..." 'face font-lock-variable-name-face))
     (gdb-init-1)
     (setq gdb-first-prompt nil))
 
-  (gdb-get-main-selected-frame)
+  (unless no-proc
+    (gdb-get-main-selected-frame))
+
   ;; We may need to update gdb-threads-list so we can use
   (gdb-get-buffer-create 'gdb-threads-buffer)
   ;; gdb-break-list is maintained in breakpoints handler
   (gdb-get-buffer-create 'gdb-breakpoints-buffer)
 
-  (gdb-emit-signal gdb-buf-publisher 'update)
+  (unless no-proc
+    (gdb-emit-signal gdb-buf-publisher 'update))
 
   (gdb-get-changed-registers)
-
   (when (and (boundp 'speedbar-frame) (frame-live-p speedbar-frame))
     (dolist (var gdb-var-list)
       (setcar (nthcdr 5 var) nil))
@@ -2045,7 +2060,7 @@ current thread and update GDB buffers."
       ;; In all-stop this updates gud-running properly as well.
       (gdb-update)
       (setq gdb-first-done-or-error nil))
-    (run-hook-with-args 'gdb-stopped-hooks result)))
+    (run-hook-with-args 'gdb-stopped-functions result)))
 
 ;; Remove the trimmings from log stream containing debugging messages
 ;; being produced by GDB's internals, use warning face and send to GUD
@@ -2085,23 +2100,28 @@ current thread and update GDB buffers."
     (setq gdb-output-sink 'emacs))
 
   (gdb-clear-partial-output)
-  (when gdb-first-done-or-error
-    (unless (or token-number gud-running)
-      (setq gdb-filter-output (concat gdb-filter-output gdb-prompt-name)))
-    (gdb-update)
-    (setq gdb-first-done-or-error nil))
 
-  (setq gdb-filter-output
-       (gdb-concat-output gdb-filter-output output-field))
+  ;; The process may already be dead (e.g. C-d at the gdb prompt).
+  (let* ((proc (get-buffer-process gud-comint-buffer))
+        (no-proc (or (null proc)
+                     (memq (process-status proc) '(exit signal)))))
 
-  (if token-number
-      (progn
-       (with-current-buffer
-           (gdb-get-buffer-create 'gdb-partial-output-buffer)
-         (funcall
-          (cdr (assoc (string-to-number token-number) gdb-handler-alist))))
-       (setq gdb-handler-alist
-             (assq-delete-all token-number gdb-handler-alist)))))
+    (when gdb-first-done-or-error
+      (unless (or token-number gud-running no-proc)
+       (setq gdb-filter-output (concat gdb-filter-output gdb-prompt-name)))
+      (gdb-update no-proc)
+      (setq gdb-first-done-or-error nil))
+
+    (setq gdb-filter-output
+         (gdb-concat-output gdb-filter-output output-field))
+
+    (when token-number
+      (with-current-buffer
+         (gdb-get-buffer-create 'gdb-partial-output-buffer)
+       (funcall
+        (cdr (assoc (string-to-number token-number) gdb-handler-alist))))
+      (setq gdb-handler-alist
+           (assq-delete-all token-number gdb-handler-alist)))))
 
 (defun gdb-concat-output (so-far new)
   (cond
@@ -4105,9 +4125,13 @@ This arrangement depends on the value of `gdb-many-windows'."
            (gud-find-file gdb-main-file)))
         (setq gdb-source-window win)))))
 
+;; Called from `gud-sentinel' in gud.el:
 (defun gdb-reset ()
   "Exit a debugging session cleanly.
 Kills the gdb buffers, and resets variables and the source buffers."
+  ;; The gdb-inferior buffer has a pty hooked up to the main gdb
+  ;; process.  This pty must be deleted explicitly.
+  (gdb-inferior-io--maybe-delete-pty)
   (dolist (buffer (buffer-list))
     (unless (eq buffer gud-comint-buffer)
       (with-current-buffer buffer