(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 "*"))))
(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)))
: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:
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)
(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)
(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))
;; 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
(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
(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