summaryrefslogtreecommitdiff
path: root/module
diff options
context:
space:
mode:
Diffstat (limited to 'module')
-rw-r--r--module/Makefile.am3
-rwxr-xr-xmodule/ice-9/gds-client.scm583
-rw-r--r--module/ice-9/gds-server.scm188
3 files changed, 0 insertions, 774 deletions
diff --git a/module/Makefile.am b/module/Makefile.am
index 0e50b7119..aad8c7080 100644
--- a/module/Makefile.am
+++ b/module/Makefile.am
@@ -183,7 +183,6 @@ ICE_9_SOURCES = \
ice-9/control.scm \
ice-9/curried-definitions.scm \
ice-9/debug.scm \
- ice-9/debugger.scm \
ice-9/documentation.scm \
ice-9/expect.scm \
ice-9/format.scm \
@@ -229,7 +228,6 @@ ICE_9_SOURCES = \
ice-9/weak-vector.scm \
ice-9/list.scm \
ice-9/serialize.scm \
- ice-9/gds-server.scm \
ice-9/vlist.scm
SRFI_SOURCES = \
@@ -346,7 +344,6 @@ LIB_SOURCES = \
EXTRA_DIST += oop/ChangeLog-2008
NOCOMP_SOURCES = \
- ice-9/gds-client.scm \
ice-9/match.upstream.scm \
ice-9/psyntax.scm \
ice-9/r6rs-libraries.scm \
diff --git a/module/ice-9/gds-client.scm b/module/ice-9/gds-client.scm
deleted file mode 100755
index 848b77485..000000000
--- a/module/ice-9/gds-client.scm
+++ /dev/null
@@ -1,583 +0,0 @@
-(define-module (ice-9 gds-client)
- #:use-module (oop goops)
- #:use-module (oop goops describe)
- #:use-module (ice-9 debugging trace)
- #:use-module (ice-9 debugging traps)
- #:use-module (ice-9 debugging trc)
- #:use-module (ice-9 debugging steps)
- #:use-module (ice-9 pretty-print)
- #:use-module (ice-9 regex)
- #:use-module (ice-9 session)
- #:use-module (ice-9 string-fun)
- #:export (gds-debug-trap
- run-utility
- gds-accept-input))
-
-(use-modules (ice-9 debugger utils))
-
-(use-modules (ice-9 debugger))
-
-(define gds-port #f)
-
-;; Return an integer that somehow identifies the current thread.
-(define (get-thread-id)
- (let ((root (dynamic-root)))
- (cond ((integer? root)
- root)
- ((pair? root)
- (object-address root))
- (else
- (error "Unexpected dynamic root:" root)))))
-
-;; gds-debug-read is a high-priority read. The (debug-thread-id ID)
-;; form causes the frontend to dismiss any reads from threads whose id
-;; is not ID, until it receives the (thread-id ...) form with the same
-;; id as ID. Dismissing the reads of any other threads (by sending a
-;; form that is otherwise ignored) causes those threads to release the
-;; read mutex, which allows the (gds-read) here to proceed.
-(define (gds-debug-read)
- (write-form `(debug-thread-id ,(get-thread-id)))
- (gds-read))
-
-(define (gds-debug-trap trap-context)
- "Invoke the GDS debugger to explore the stack at the specified trap."
- (connect-to-gds)
- (start-stack 'debugger
- (let* ((stack (tc:stack trap-context))
- (flags1 (let ((trap-type (tc:type trap-context)))
- (case trap-type
- ((#:return #:error)
- (list trap-type
- (tc:return-value trap-context)))
- (else
- (list trap-type)))))
- (flags (if (tc:continuation trap-context)
- (cons #:continuable flags1)
- flags1))
- (fired-traps (tc:fired-traps trap-context))
- (special-index (and (= (length fired-traps) 1)
- (is-a? (car fired-traps) <exit-trap>)
- (eq? (tc:type trap-context) #:return)
- (- (tc:depth trap-context)
- (slot-ref (car fired-traps) 'depth)))))
- ;; Write current stack to the frontend.
- (write-form (list 'stack
- (if (and special-index (> special-index 0))
- special-index
- 0)
- (stack->emacs-readable stack)
- (append (flags->emacs-readable flags)
- (slot-ref trap-context
- 'handler-return-syms))))
- ;; Now wait for instruction.
- (let loop ((protocol (gds-debug-read)))
- ;; Act on it.
- (case (car protocol)
- ((tweak)
- ;; Request to tweak the handler return value.
- (let ((tweaking (catch #t
- (lambda ()
- (list (with-input-from-string
- (cadr protocol)
- read)))
- (lambda ignored #f))))
- (if tweaking
- (slot-set! trap-context
- 'handler-return-value
- (cons 'instead (car tweaking)))))
- (loop (gds-debug-read)))
- ((continue)
- ;; Continue (by exiting the debugger).
- *unspecified*)
- ((evaluate)
- ;; Evaluate expression in specified frame.
- (eval-in-frame stack (cadr protocol) (caddr protocol))
- (loop (gds-debug-read)))
- ((info-frame)
- ;; Return frame info.
- (let ((frame (stack-ref stack (cadr protocol))))
- (write-form (list 'info-result
- (with-output-to-string
- (lambda ()
- (write-frame-long frame))))))
- (loop (gds-debug-read)))
- ((info-args)
- ;; Return frame args.
- (let ((frame (stack-ref stack (cadr protocol))))
- (write-form (list 'info-result
- (with-output-to-string
- (lambda ()
- (write-frame-args-long frame))))))
- (loop (gds-debug-read)))
- ((proc-source)
- ;; Show source of application procedure.
- (let* ((frame (stack-ref stack (cadr protocol)))
- (proc (frame-procedure frame))
- (source (and proc (procedure-source proc))))
- (write-form (list 'info-result
- (if source
- (sans-surrounding-whitespace
- (with-output-to-string
- (lambda ()
- (pretty-print source))))
- (if proc
- "This procedure is coded in C"
- "This frame has no procedure")))))
- (loop (gds-debug-read)))
- ((traps-here)
- ;; Show the traps that fired here.
- (write-form (list 'info-result
- (with-output-to-string
- (lambda ()
- (for-each describe
- (tc:fired-traps trap-context))))))
- (loop (gds-debug-read)))
- ((step-into)
- ;; Set temporary breakpoint on next trap.
- (at-step gds-debug-trap
- 1
- #f
- (if (memq #:return flags)
- #f
- (- (stack-length stack)
- (cadr protocol)))))
- ((step-over)
- ;; Set temporary breakpoint on exit from
- ;; specified frame.
- (at-exit (- (stack-length stack) (cadr protocol))
- gds-debug-trap))
- ((step-file)
- ;; Set temporary breakpoint on next trap in same
- ;; source file.
- (at-step gds-debug-trap
- 1
- (frame-file-name (stack-ref stack
- (cadr protocol)))
- (if (memq #:return flags)
- #f
- (- (stack-length stack)
- (cadr protocol)))))
- (else
- (safely-handle-nondebug-protocol protocol)
- (loop (gds-debug-read))))))))
-
-(define (connect-to-gds . application-name)
- (or gds-port
- (let ((gds-unix-socket-name (getenv "GDS_UNIX_SOCKET_NAME")))
- (set! gds-port
- (or (and gds-unix-socket-name
- (false-if-exception
- (let ((s (socket PF_UNIX SOCK_STREAM 0)))
- (connect s AF_UNIX gds-unix-socket-name)
- s)))
- (false-if-exception
- (let ((s (socket PF_INET SOCK_STREAM 0))
- (SOL_TCP 6)
- (TCP_NODELAY 1))
- (setsockopt s SOL_TCP TCP_NODELAY 1)
- (connect s AF_INET (inet-aton "127.0.0.1") 8333)
- s))
- (error "Couldn't connect to GDS by TCP or Unix domain socket")))
- (write-form (list 'name (getpid) (apply client-name application-name))))))
-
-(define (client-name . application-name)
- (let loop ((args (append application-name (program-arguments))))
- (if (null? args)
- (format #f "PID ~A" (getpid))
- (let ((arg (car args)))
- (cond ((string-match "^(.*[/\\])?guile(\\..*)?$" arg)
- (loop (cdr args)))
- ((string-match "^-" arg)
- (loop (cdr args)))
- (else
- (format #f "~A (PID ~A)" arg (getpid))))))))
-
-;;(if (not (defined? 'make-mutex))
-;; (begin
-;; (define (make-mutex) #f)
-;; (define lock-mutex noop)
-;; (define unlock-mutex noop)))
-
-(define write-mutex (make-mutex))
-
-(define (write-form form)
- ;; Write any form FORM to GDS.
- (lock-mutex write-mutex)
- (write form gds-port)
- (newline gds-port)
- (force-output gds-port)
- (unlock-mutex write-mutex))
-
-(define (stack->emacs-readable stack)
- ;; Return Emacs-readable representation of STACK.
- (map (lambda (index)
- (frame->emacs-readable (stack-ref stack index)))
- (iota (min (stack-length stack)
- (cadr (memq 'depth (debug-options)))))))
-
-(define (frame->emacs-readable frame)
- ;; Return Emacs-readable representation of FRAME.
- (if (frame-procedure? frame)
- (list 'application
- (with-output-to-string
- (lambda ()
- (display (if (frame-real? frame) " " "t "))
- (write-frame-short/application frame)))
- (source->emacs-readable frame))
- (list 'evaluation
- (with-output-to-string
- (lambda ()
- (display (if (frame-real? frame) " " "t "))
- (write-frame-short/expression frame)))
- (source->emacs-readable frame))))
-
-(define (source->emacs-readable frame)
- ;; Return Emacs-readable representation of the filename, line and
- ;; column source properties of SOURCE.
- (or (frame->source-position frame) 'nil))
-
-(define (flags->emacs-readable flags)
- ;; Return Emacs-readable representation of trap FLAGS.
- (let ((prev #f))
- (map (lambda (flag)
- (let ((erf (if (and (keyword? flag)
- (not (eq? prev #:return)))
- (keyword->symbol flag)
- (format #f "~S" flag))))
- (set! prev flag)
- erf))
- flags)))
-
-;; FIXME: the new evaluator breaks this, by removing local-eval. Need to
-;; figure out our story in this regard.
-(define (eval-in-frame stack index expr)
- (write-form
- (list 'eval-result
- (format #f "~S"
- (catch #t
- (lambda ()
- (local-eval (with-input-from-string expr read)
- (memoized-environment
- (frame-source (stack-ref stack
- index)))))
- (lambda args
- (cons 'ERROR args)))))))
-
-(set! (behaviour-ordering gds-debug-trap) 100)
-
-;;; Code below here adds support for interaction between the GDS
-;;; client program and the Emacs frontend even when not stopped in the
-;;; debugger.
-
-;; A mutex to control attempts by multiple threads to read protocol
-;; back from the frontend.
-(define gds-read-mutex (make-mutex))
-
-;; Read a protocol instruction from the frontend.
-(define (gds-read)
- ;; Acquire the read mutex.
- (lock-mutex gds-read-mutex)
- ;; Tell the front end something that identifies us as a thread.
- (write-form `(thread-id ,(get-thread-id)))
- ;; Now read, then release the mutex and return what was read.
- (let ((x (catch #t
- (lambda () (read gds-port))
- (lambda ignored the-eof-object))))
- (unlock-mutex gds-read-mutex)
- x))
-
-(define (gds-accept-input exit-on-continue)
- ;; If reading from the GDS connection returns EOF, we will throw to
- ;; this catch.
- (catch 'server-eof
- (lambda ()
- (let loop ((protocol (gds-read)))
- (if (or (eof-object? protocol)
- (and exit-on-continue
- (eq? (car protocol) 'continue)))
- (throw 'server-eof))
- (safely-handle-nondebug-protocol protocol)
- (loop (gds-read))))
- (lambda ignored #f)))
-
-(define (safely-handle-nondebug-protocol protocol)
- ;; This catch covers any internal errors in the GDS code or
- ;; protocol.
- (catch #t
- (lambda ()
- (lazy-catch #t
- (lambda ()
- (handle-nondebug-protocol protocol))
- save-lazy-trap-context-and-rethrow))
- (lambda (key . args)
- (write-form
- `(eval-results (error . ,(format #f "~s" protocol))
- ,(if last-lazy-trap-context 't 'nil)
- "GDS Internal Error
-Please report this to <neil@ossau.uklinux.net>, ideally including:
-- a description of the scenario in which this error occurred
-- which versions of Guile and guile-debugging you are using
-- the error stack, which you can get by clicking on the link below,
- and then cut and paste into your report.
-Thanks!\n\n"
- ,(list (with-output-to-string
- (lambda ()
- (write key)
- (display ": ")
- (write args)
- (newline)))))))))
-
-;; The key that is used to signal a read error changes from 1.6 to
-;; 1.8; here we cover all eventualities by discovering the key
-;; dynamically.
-(define read-error-key
- (catch #t
- (lambda ()
- (with-input-from-string "(+ 3 4" read))
- (lambda (key . args)
- key)))
-
-(define (handle-nondebug-protocol protocol)
- (case (car protocol)
-
- ((eval)
- (set! last-lazy-trap-context #f)
- (apply (lambda (correlator module port-name line column code flags)
- (with-input-from-string code
- (lambda ()
- (set-port-filename! (current-input-port) port-name)
- (set-port-line! (current-input-port) line)
- (set-port-column! (current-input-port) column)
- (let ((m (and module (resolve-module-from-root module))))
- (catch read-error-key
- (lambda ()
- (let loop ((exprs '()) (x (read)))
- (if (eof-object? x)
- ;; Expressions to be evaluated have all
- ;; been read. Now evaluate them.
- (let loop2 ((exprs (reverse! exprs))
- (results '())
- (n 1))
- (if (null? exprs)
- (write-form `(eval-results ,correlator
- ,(if last-lazy-trap-context 't 'nil)
- ,@results))
- (loop2 (cdr exprs)
- (append results (gds-eval (car exprs) m
- (if (and (null? (cdr exprs))
- (= n 1))
- #f n)))
- (+ n 1))))
- ;; Another complete expression read; add
- ;; it to the list.
- (begin
- (if (and (pair? x)
- (memq 'debug flags))
- (install-trap (make <source-trap>
- #:expression x
- #:behaviour gds-debug-trap)))
- (loop (cons x exprs) (read))))))
- (lambda (key . args)
- (write-form `(eval-results
- ,correlator
- ,(if last-lazy-trap-context 't 'nil)
- ,(with-output-to-string
- (lambda ()
- (display ";;; Reading expressions")
- (display " to evaluate\n")
- (apply display-error #f
- (current-output-port) args)))
- ("error-in-read")))))))))
- (cdr protocol)))
-
- ((complete)
- (let ((matches (apropos-internal
- (string-append "^" (regexp-quote (cadr protocol))))))
- (cond ((null? matches)
- (write-form '(completion-result nil)))
- (else
- ;;(write matches (current-error-port))
- ;;(newline (current-error-port))
- (let ((match
- (let loop ((match (symbol->string (car matches)))
- (matches (cdr matches)))
- ;;(write match (current-error-port))
- ;;(newline (current-error-port))
- ;;(write matches (current-error-port))
- ;;(newline (current-error-port))
- (if (null? matches)
- match
- (if (string-prefix=? match
- (symbol->string (car matches)))
- (loop match (cdr matches))
- (loop (substring match 0
- (- (string-length match) 1))
- matches))))))
- (if (string=? match (cadr protocol))
- (write-form `(completion-result
- ,(map symbol->string matches)))
- (write-form `(completion-result
- ,match))))))))
-
- ((debug-lazy-trap-context)
- (if last-lazy-trap-context
- (gds-debug-trap last-lazy-trap-context)
- (error "There is no stack available to show")))
-
- (else
- (error "Unexpected protocol:" protocol))))
-
-(define (resolve-module-from-root name)
- (save-module-excursion
- (lambda ()
- (set-current-module the-root-module)
- (resolve-module name))))
-
-(define (gds-eval x m part)
- ;; Consumer to accept possibly multiple values and present them for
- ;; Emacs as a list of strings.
- (define (value-consumer . values)
- (if (unspecified? (car values))
- '()
- (map (lambda (value)
- (with-output-to-string (lambda () (write value))))
- values)))
- ;; Now do evaluation.
- (let ((intro (if part
- (format #f ";;; Evaluating expression ~A" part)
- ";;; Evaluating"))
- (value #f))
- (let* ((do-eval (if m
- (lambda ()
- (display intro)
- (display " in module ")
- (write (module-name m))
- (newline)
- (set! value
- (call-with-values (lambda ()
- (start-stack 'gds-eval-stack
- (eval x m)))
- value-consumer)))
- (lambda ()
- (display intro)
- (display " in current module ")
- (write (module-name (current-module)))
- (newline)
- (set! value
- (call-with-values (lambda ()
- (start-stack 'gds-eval-stack
- (primitive-eval x)))
- value-consumer)))))
- (output
- (with-output-to-string
- (lambda ()
- (catch #t
- (lambda ()
- (lazy-catch #t
- do-eval
- save-lazy-trap-context-and-rethrow))
- (lambda (key . args)
- (case key
- ((misc-error signal unbound-variable numerical-overflow)
- (apply display-error #f
- (current-output-port) args)
- (set! value '("error-in-evaluation")))
- (else
- (display "EXCEPTION: ")
- (display key)
- (display " ")
- (write args)
- (newline)
- (set! value
- '("unhandled-exception-in-evaluation"))))))))))
- (list output value))))
-
-(define last-lazy-trap-context #f)
-
-(define (save-lazy-trap-context-and-rethrow key . args)
- (set! last-lazy-trap-context
- (throw->trap-context key args save-lazy-trap-context-and-rethrow))
- (apply throw key args))
-
-(define (run-utility)
- (connect-to-gds)
- (write (getpid))
- (newline)
- (force-output)
- (module-use! (resolve-module '(guile-user))
- (resolve-interface '(ice-9 session)))
- (gds-accept-input #f))
-
-(define-method (trap-description (trap <trap>))
- (let loop ((description (list (class-name (class-of trap))))
- (next 'installed?))
- (case next
- ((installed?)
- (loop (if (slot-ref trap 'installed)
- (cons 'installed description)
- description)
- 'conditional?))
- ((conditional?)
- (loop (if (slot-ref trap 'condition)
- (cons 'conditional description)
- description)
- 'skip-count))
- ((skip-count)
- (loop (let ((skip-count (slot-ref trap 'skip-count)))
- (if (zero? skip-count)
- description
- (cons* skip-count 'skip-count description)))
- 'single-shot?))
- ((single-shot?)
- (loop (if (slot-ref trap 'single-shot)
- (cons 'single-shot description)
- description)
- 'done))
- (else
- (reverse! description)))))
-
-(define-method (trap-description (trap <procedure-trap>))
- (let ((description (next-method)))
- (set-cdr! description
- (cons (procedure-name (slot-ref trap 'procedure))
- (cdr description)))
- description))
-
-(define-method (trap-description (trap <source-trap>))
- (let ((description (next-method)))
- (set-cdr! description
- (cons (format #f "~s" (slot-ref trap 'expression))
- (cdr description)))
- description))
-
-(define-method (trap-description (trap <location-trap>))
- (let ((description (next-method)))
- (set-cdr! description
- (cons* (slot-ref trap 'file-regexp)
- (slot-ref trap 'line)
- (slot-ref trap 'column)
- (cdr description)))
- description))
-
-(define (gds-trace-trap trap-context)
- (connect-to-gds)
- (gds-do-trace trap-context)
- (at-exit (tc:depth trap-context) gds-do-trace))
-
-(define (gds-do-trace trap-context)
- (write-form (list 'trace
- (format #f
- "~3@a: ~a"
- (trace/stack-real-depth trap-context)
- (trace/info trap-context)))))
-
-(define (gds-trace-subtree trap-context)
- (connect-to-gds)
- (gds-do-trace trap-context)
- (let ((step-trap (make <step-trap> #:behaviour gds-do-trace)))
- (install-trap step-trap)
- (at-exit (tc:depth trap-context)
- (lambda (trap-context)
- (uninstall-trap step-trap)))))
-
-;;; (ice-9 gds-client) ends here.
diff --git a/module/ice-9/gds-server.scm b/module/ice-9/gds-server.scm
deleted file mode 100644
index 5ec867535..000000000
--- a/module/ice-9/gds-server.scm
+++ /dev/null
@@ -1,188 +0,0 @@
-;;;; Guile Debugger UI server
-
-;;; Copyright (C) 2003 Free Software Foundation, Inc.
-;;;
-;;;; This library is free software; you can redistribute it and/or
-;;;; modify it under the terms of the GNU Lesser General Public
-;;;; License as published by the Free Software Foundation; either
-;;;; version 3 of the License, or (at your option) any later version.
-;;;;
-;;;; This library is distributed in the hope that it will be useful,
-;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-;;;; Lesser General Public License for more details.
-;;;;
-;;;; You should have received a copy of the GNU Lesser General Public
-;;;; License along with this library; if not, write to the Free Software
-;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-(define-module (ice-9 gds-server)
- #:export (run-server))
-
-;; UI is normally via a pipe to Emacs, so make sure to flush output
-;; every time we write.
-(define (write-to-ui form)
- (write form)
- (newline)
- (force-output))
-
-(define (trc . args)
- (write-to-ui (cons '* args)))
-
-(define (with-error->eof proc port)
- (catch #t
- (lambda () (proc port))
- (lambda args the-eof-object)))
-
-(define connection->id (make-object-property))
-
-(define (run-server unix-socket-name tcp-port)
-
- (let ((unix-server (socket PF_UNIX SOCK_STREAM 0))
- (tcp-server (socket PF_INET SOCK_STREAM 0)))
-
- ;; Bind and start listening on the Unix domain socket.
- (false-if-exception (delete-file unix-socket-name))
- (bind unix-server AF_UNIX unix-socket-name)
- (listen unix-server 5)
-
- ;; Bind and start listening on the TCP socket.
- (setsockopt tcp-server SOL_SOCKET SO_REUSEADDR 1)
- (false-if-exception (bind tcp-server AF_INET INADDR_ANY tcp-port))
- (listen tcp-server 5)
-
- ;; Main loop.
- (let loop ((clients '()) (readable-sockets '()))
-
- (define (do-read port)
- (cond ((eq? port (current-input-port))
- (do-read-from-ui))
- ((eq? port unix-server)
- (accept-new-client unix-server))
- ((eq? port tcp-server)
- (accept-new-client tcp-server))
- (else
- (do-read-from-client port))))
-
- (define (do-read-from-ui)
- (trc "reading from ui")
- (let* ((form (with-error->eof read (current-input-port)))
- (client (assq-ref (map (lambda (port)
- (cons (connection->id port) port))
- clients)
- (car form))))
- (with-error->eof read-char (current-input-port))
- (if client
- (begin
- (write (cdr form) client)
- (newline client))
- (trc "client not found")))
- clients)
-
- (define (accept-new-client server)
- (let ((new-port (car (accept server))))
- ;; Read the client's ID.
- (let ((name-form (read new-port)))
- ;; Absorb the following newline character.
- (read-char new-port)
- ;; Check that we have a name form.
- (or (eq? (car name-form) 'name)
- (error "Invalid name form:" name-form))
- ;; Store an association from the connection to the ID.
- (set! (connection->id new-port) (cadr name-form))
- ;; Pass the name form on to Emacs.
- (write-to-ui (cons (connection->id new-port) name-form)))
- ;; Add the new connection to the set that we select on.
- (cons new-port clients)))
-
- (define (do-read-from-client port)
- (trc "reading from client")
- (let ((next-char (with-error->eof peek-char port)))
- ;;(trc 'next-char next-char)
- (cond ((eof-object? next-char)
- (write-to-ui (list (connection->id port) 'closed))
- (close port)
- (delq port clients))
- ((char=? next-char #\()
- (write-to-ui (cons (connection->id port)
- (with-error->eof read port)))
- clients)
- (else
- (with-error->eof read-char port)
- clients))))
-
- ;;(trc 'clients clients)
- ;;(trc 'readable-sockets readable-sockets)
-
- (if (null? readable-sockets)
- (loop clients (car (select (cons* (current-input-port)
- unix-server
- tcp-server
- clients)
- '()
- '())))
- (loop (do-read (car readable-sockets)) (cdr readable-sockets))))))
-
-;; What happens if there are multiple copies of Emacs running on the
-;; same machine, and they all try to start up the GDS server? They
-;; can't all listen on the same TCP port, so the short answer is that
-;; all of them except the first will get an EADDRINUSE error when
-;; trying to bind.
-;;
-;; We want to be able to handle this scenario, though, so that Scheme
-;; code can be evaluated, and help invoked, in any of those Emacsen.
-;; So we introduce the idea of a "slave server". When a new GDS
-;; server gets an EADDRINUSE bind error, the implication is that there
-;; is already a GDS server running, so the new server instead connects
-;; to the existing one (by issuing a connect to the GDS port number).
-;;
-;; Let's call the first server the "master", and the new one the
-;; "slave". In principle the master can now proxy any GDS client
-;; connections through to the slave, so long as there is sufficient
-;; information in the protocol for it to decide when and how to do
-;; this.
-;;
-;; The basic information and mechanism that we need for this is as
-;; follows.
-;;
-;; - A unique ID for each Emacs; this can be each Emacs's PID. When a
-;; slave server connects to the master, it announces itself by sending
-;; the protocol (emacs ID).
-;;
-;; - A way for a client to indicate which Emacs it wants to use. At
-;; the protocol level, this is an extra argument in the (name ...)
-;; protocol. (The absence of this argument means "no preference". A
-;; simplistic master server might then decide to use its own Emacs; a
-;; cleverer one might monitor which Emacs appears to be most in use,
-;; and use that one.) At the API level this can be an optional
-;; argument to the `gds-connect' procedure, and the Emacs GDS code
-;; would obviously set this argument when starting a client from
-;; within Emacs.
-;;
-;; We also want a strategy for continuing seamlessly if the master
-;; server shuts down.
-;;
-;; - Each slave server will detect this as an error on the connection
-;; to the master socket. Each server then tries to bind to the GDS
-;; port again (a race which the OS will resolve), and if that fails,
-;; connect again. The result of this is that there should be a new
-;; master, and the others all slaves connected to the new master.
-;;
-;; - Each client will also detect this as an error on the connection
-;; to the (master) server. Either the client should try to connect
-;; again (perhaps after a short delay), or the reconnection can be
-;; delayed until the next time that the client requires the server.
-;; (Probably the latter, all done within `gds-read'.)
-;;
-;; (Historical note: Before this master-slave idea, clients were
-;; identified within gds-server.scm and gds*.el by an ID which was
-;; actually the file descriptor of their connection to the server.
-;; That is no good in the new scheme, because each client's ID must
-;; persist when the master server changes, so we now use the client's
-;; PID instead. We didn't use PID before because the client/server
-;; code was written to be completely asynchronous, which made it
-;; tricky for the server to discover each client's PID and associate
-;; it with a particular connection. Now we solve that problem by
-;; handling the initial protocol exchange synchronously.)
-(define (run-slave-server port)
- 'not-implemented)