guile-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Guile-commits] GNU Guile branch, master, updated. release_1-9-12-184-ga


From: Andy Wingo
Subject: [Guile-commits] GNU Guile branch, master, updated. release_1-9-12-184-ga531e76
Date: Sun, 10 Oct 2010 11:12:49 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU Guile".

http://git.savannah.gnu.org/cgit/guile.git/commit/?id=a531e76a74d4517aec0888d38d3c5e412ce67d1a

The branch, master has been updated
       via  a531e76a74d4517aec0888d38d3c5e412ce67d1a (commit)
       via  d30542c2b7e52be9e5293b4d4ef065c64316872c (commit)
       via  b2456dd434fd9b65cd9ac68bb487ee81863adf8d (commit)
       via  1924145df58c3fbaae56610e06b430508d5d169f (commit)
       via  41e826492a44d66b6056818c5718164f1d7d065b (commit)
      from  a627100bf39c64f986536e9faff564e5602e0efa (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit a531e76a74d4517aec0888d38d3c5e412ce67d1a
Author: Andy Wingo <address@hidden>
Date:   Sun Oct 10 12:56:53 2010 +0200

    add --listen command line argument.
    
    * libguile/script.c (scm_shell_usage, scm_compile_shell_switches): Add a
      --listen argument to spawn a REPL server, possibly specifying the port
      or path to listen on. The goal is for this to be the default way to
      allow debugging via Emacs or simply using netcat.

commit d30542c2b7e52be9e5293b4d4ef065c64316872c
Author: Andy Wingo <address@hidden>
Date:   Sun Oct 10 12:15:34 2010 +0200

    add (system repl server)
    
    * module/system/repl/server.scm: New module, listens on a socket for
      connections, then serves repls to those sockets.
    
    * module/Makefile.am: Add repl server.

commit b2456dd434fd9b65cd9ac68bb487ee81863adf8d
Author: Andy Wingo <address@hidden>
Date:   Sun Oct 10 12:13:04 2010 +0200

    fix segfaults when closing the current input port
    
    * libguile/ports.c (scm_char_ready_p, scm_peek_char, scm_unread_char)
      (scm_unread_string): Always validate the port, even in the case that
      we get it the default current-input-port. Otherwise the following
      causes a segfault:
    
        (begin (close-port (current-input-port)) (peek-char))

commit 1924145df58c3fbaae56610e06b430508d5d169f
Author: Andy Wingo <address@hidden>
Date:   Sun Oct 10 11:49:50 2010 +0200

    readline repl-reader falls back to boot-9 definition for other ports
    
    * guile-readline/ice-9/readline.scm (readline-repl-reader): Pull
      definition out of activate-readline. If the current input port is not
      the readline port, fall back to the boot-9 repl reader.
      (activate-readline): Adapt.

commit 41e826492a44d66b6056818c5718164f1d7d065b
Author: Andy Wingo <address@hidden>
Date:   Sun Oct 10 11:24:29 2010 +0200

    interrupted syscalls run asyncs before throwing syserror
    
    * libguile/error.c (scm_syserror, scm_syserror_msg): Run pending pending
      asyncs before throwing the error, as one of the asyncs might be a
      signal handler. But there is unfortunately a race here, as noted in a
      comment.

-----------------------------------------------------------------------

Summary of changes:
 guile-readline/ice-9/readline.scm |   43 +++++++-----
 libguile/error.c                  |   32 +++++++++
 libguile/ports.c                  |   14 ++--
 libguile/script.c                 |   56 ++++++++++++++++
 module/Makefile.am                |    3 +-
 module/system/repl/server.scm     |  131 +++++++++++++++++++++++++++++++++++++
 6 files changed, 252 insertions(+), 27 deletions(-)
 create mode 100644 module/system/repl/server.scm

diff --git a/guile-readline/ice-9/readline.scm 
b/guile-readline/ice-9/readline.scm
index 38fb23f..4879bab 100644
--- a/guile-readline/ice-9/readline.scm
+++ b/guile-readline/ice-9/readline.scm
@@ -200,26 +200,33 @@
        (lambda ()
          (set! *readline-completion-function* old-completer)))))
 
+(define readline-repl-reader
+  (let ((boot-9-repl-reader repl-reader))
+    (lambda* (repl-prompt #:optional (reader (fluid-ref current-reader)))
+      (let ((port (current-input-port)))
+        (if (eq? port (readline-port))
+            (let ((outer-new-input-prompt new-input-prompt)
+                  (outer-continuation-prompt continuation-prompt)
+                  (outer-read-hook read-hook))
+              (dynamic-wind
+                (lambda ()
+                  (set-buffered-input-continuation?! port #f)
+                  (set-readline-prompt! repl-prompt "... ")
+                  (set-readline-read-hook! (lambda ()
+                                             (run-hook before-read-hook))))
+                (lambda () ((or reader read) port))
+                (lambda ()
+                  (set-readline-prompt! outer-new-input-prompt
+                                        outer-continuation-prompt)
+                  (set-readline-read-hook! outer-read-hook))))
+            (boot-9-repl-reader repl-prompt reader))))))
+
 (define-public (activate-readline)
   (if (isatty? (current-input-port))
-      (let ((repl-read-hook (lambda () (run-hook before-read-hook))))
-       (set-current-input-port (readline-port))
-       (set! repl-reader
-             (lambda* (repl-prompt
-                        #:optional (reader (fluid-ref current-reader)))
-               (let ((outer-new-input-prompt new-input-prompt)
-                     (outer-continuation-prompt continuation-prompt)
-                     (outer-read-hook read-hook))
-                 (dynamic-wind
-                    (lambda ()
-                      (set-buffered-input-continuation?! (readline-port) #f)
-                      (set-readline-prompt! repl-prompt "... ")
-                      (set-readline-read-hook! repl-read-hook))
-                    (lambda () ((or reader read) (current-input-port)))
-                    (lambda ()
-                      (set-readline-prompt! outer-new-input-prompt 
outer-continuation-prompt)
-                      (set-readline-read-hook! outer-read-hook))))))
-       (set! (using-readline?) #t))))
+      (begin
+        (set-current-input-port (readline-port))
+        (set! repl-reader readline-repl-reader)
+        (set! (using-readline?) #t))))
 
 (define-public (make-completion-function strings)
   "Construct and return a completion function for a list of strings.
diff --git a/libguile/error.c b/libguile/error.c
index 4b6bab8..b4ed7d0 100644
--- a/libguile/error.c
+++ b/libguile/error.c
@@ -147,6 +147,33 @@ void
 scm_syserror (const char *subr)
 {
   SCM err = scm_from_int (SCM_I_ERRNO ());
+
+  /* It could be that we're getting here because the syscall was
+     interrupted by a signal.  In that case a signal handler might have
+     been queued to run.  The signal handler probably throws an
+     exception.
+
+     If we don't try to run the signal handler now, it will run later,
+     which would result in two exceptions being thrown: this syserror,
+     and then at some later time the exception thrown by the async
+     signal handler.
+
+     The problem is that we don't know if handling the signal caused an
+     async to be queued.  By this time scmsigs.c:take_signal will have
+     written a byte on the fd, but we don't know if the signal-handling
+     thread has read it off and queued an async.
+
+     Ideally we need some API like scm_i_ensure_signals_delivered() to
+     catch up signal delivery.  Barring that, we just cross our digits
+     and pray; it could be that we handle the signal in time, and just
+     throw once, or it could be that we miss the deadline and throw
+     twice.
+  */
+#ifdef EINTR
+  if (scm_to_int (err) == EINTR)
+    SCM_ASYNC_TICK;
+#endif
+
   scm_error (scm_system_error_key,
             subr,
             "~A",
@@ -157,6 +184,11 @@ scm_syserror (const char *subr)
 void
 scm_syserror_msg (const char *subr, const char *message, SCM args, int eno)
 {
+  /* See above note about the EINTR signal handling race. */
+#ifdef EINTR
+  if (eno == EINTR)
+    SCM_ASYNC_TICK;
+#endif
   scm_error (scm_system_error_key,
             subr,
             message,
diff --git a/libguile/ports.c b/libguile/ports.c
index 6cf0de2..7fabc81 100644
--- a/libguile/ports.c
+++ b/libguile/ports.c
@@ -261,8 +261,9 @@ SCM_DEFINE (scm_char_ready_p, "char-ready?", 0, 1, 0,
 
   if (SCM_UNBNDP (port))
     port = scm_current_input_port ();
-  else
-    SCM_VALIDATE_OPINPORT (1, port);
+  /* It's possible to close the current input port, so validate even in
+     this case. */
+  SCM_VALIDATE_OPINPORT (1, port);
 
   pt = SCM_PTAB_ENTRY (port);
 
@@ -1656,8 +1657,7 @@ SCM_DEFINE (scm_peek_char, "peek-char", 0, 1, 0,
 
   if (SCM_UNBNDP (port))
     port = scm_current_input_port ();
-  else
-    SCM_VALIDATE_OPINPORT (1, port);
+  SCM_VALIDATE_OPINPORT (1, port);
 
   column = SCM_COL (port);
   line = SCM_LINUM (port);
@@ -1695,8 +1695,7 @@ SCM_DEFINE (scm_unread_char, "unread-char", 1, 1, 0,
   SCM_VALIDATE_CHAR (1, cobj);
   if (SCM_UNBNDP (port))
     port = scm_current_input_port ();
-  else
-    SCM_VALIDATE_OPINPORT (2, port);
+  SCM_VALIDATE_OPINPORT (2, port);
 
   c = SCM_CHAR (cobj);
 
@@ -1717,8 +1716,7 @@ SCM_DEFINE (scm_unread_string, "unread-string", 2, 0, 0,
   SCM_VALIDATE_STRING (1, str);
   if (SCM_UNBNDP (port))
     port = scm_current_input_port ();
-  else
-    SCM_VALIDATE_OPINPORT (2, port);
+  SCM_VALIDATE_OPINPORT (2, port);
 
   n = scm_i_string_length (str);
 
diff --git a/libguile/script.c b/libguile/script.c
index 318e5aa..caf3ac6 100644
--- a/libguile/script.c
+++ b/libguile/script.c
@@ -386,6 +386,8 @@ scm_shell_usage (int fatal, char *message)
            "  --no-autocompile  disable automatic source file compilation\n"
            "                 Default is to enable autocompilation of source\n"
            "                 files.\n"
+           "  --listen[=P]   Listen on a local port or a path for REPL 
clients.\n"
+           "                 If P is not given, the default is local port 
37146.\n"
           "  -q             inhibit loading of user init file\n"
           "  --use-srfi=LS  load SRFI modules for the SRFIs in LS,\n"
           "                 which is a list of numbers like \"2,13,14\"\n"
@@ -640,6 +642,60 @@ scm_compile_shell_switches (int argc, char **argv)
                           tail);
        }
 
+      else if (! strncmp (argv[i], "--listen", 8)  /* start a repl server */ 
+               && (argv[i][8] == '\0' || argv[i][8] == '='))
+       {
+          const char default_template[] =
+            "(@@ (system repl server) (spawn-server))";
+          const char port_template[] =
+            "(@@ (system repl server)"
+            "    (spawn-server (make-tcp-server-socket #:port ~a)))";
+          const char path_template[] =
+            "(@@ (system repl server)"
+            "    (spawn-server (make-unix-domain-server-socket #:path ~s)))";
+
+         SCM form_str = SCM_BOOL_F;
+         char * p = argv[i] + 8;
+
+          if (*p == '=')
+            {
+              p++;
+              if (*p > '0' && *p <= '9')
+                {
+                  /* --listen=PORT */
+                  SCM port = scm_string_to_number (scm_from_locale_string (p),
+                                                   SCM_UNDEFINED);
+
+                  if (scm_is_false (port))
+                    scm_shell_usage (1, "invalid port for --listen");
+
+                  form_str =
+                    scm_simple_format (SCM_BOOL_F,
+                                       scm_from_locale_string (port_template),
+                                       scm_list_1 (port));
+                }
+              else if (*p == '/')
+                {
+                  /* --listen=/PATH/TO/SOCKET */
+                  SCM path = scm_from_locale_string (p);
+
+                  form_str =
+                    scm_simple_format (SCM_BOOL_F,
+                                       scm_from_locale_string (path_template),
+                                       scm_list_1 (path));
+                }
+              else
+                {
+                  /* unknown --listen arg */
+                  scm_shell_usage (1, "unknown argument to --listen");
+                }
+            }
+          else
+            form_str = scm_from_locale_string (default_template);
+          
+          tail = scm_cons (scm_read (scm_open_input_string (form_str)), tail);
+       }
+
       else if (! strcmp (argv[i], "-h")
               || ! strcmp (argv[i], "--help"))
        {
diff --git a/module/Makefile.am b/module/Makefile.am
index 9aa4c7a..a11a1d5 100644
--- a/module/Makefile.am
+++ b/module/Makefile.am
@@ -324,7 +324,8 @@ SYSTEM_SOURCES =                            \
   system/repl/error-handling.scm               \
   system/repl/common.scm                       \
   system/repl/command.scm                      \
-  system/repl/repl.scm
+  system/repl/repl.scm                         \
+  system/repl/server.scm
 
 LIB_SOURCES =                                  \
   statprof.scm                                 \
diff --git a/module/system/repl/server.scm b/module/system/repl/server.scm
new file mode 100644
index 0000000..132ea81
--- /dev/null
+++ b/module/system/repl/server.scm
@@ -0,0 +1,131 @@
+;;; Repl server
+
+;; Copyright (C)  2003, 2010 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
+
+;;; Code:
+
+(define-module (system repl server)
+  #:use-module (system repl repl)
+  #:use-module (ice-9 threads)
+  #:export (make-tcp-server-socket
+            make-unix-domain-server-socket
+            run-server
+            spawn-server
+            stop-server-and-clients!))
+
+(define *open-sockets* '())
+
+(define sockets-lock (make-mutex))
+
+(define (close-socket! s)
+  (with-mutex sockets-lock
+    (set! *open-sockets* (delq! s *open-sockets*)))
+  ;; Close-port could block or raise an exception flushing buffered
+  ;; output.  Hmm.
+  (close-port s))
+
+(define (add-open-socket! s)
+  (with-mutex sockets-lock
+    (set! *open-sockets* (cons s *open-sockets*))))
+
+(define (stop-server-and-clients!)
+  (cond
+   ((with-mutex sockets-lock
+      (and (pair? *open-sockets*)
+           (car *open-sockets*)))
+    => (lambda (s)
+         (close-socket! s)
+         (stop-server-and-clients!)))))
+
+(define* (make-tcp-server-socket #:key
+                          (host #f)
+                          (addr (if host (inet-aton host) INADDR_LOOPBACK))
+                          (port 37146))
+  (let ((sock (socket PF_INET SOCK_STREAM 0)))
+    (setsockopt sock SOL_SOCKET SO_REUSEADDR 1)
+    (bind sock AF_INET addr port)
+    sock))
+
+(define* (make-unix-domain-server-socket #:key (path "/tmp/guile-socket"))
+  (let ((sock (socket PF_UNIX SOCK_STREAM 0)))
+    (setsockopt sock SOL_SOCKET SO_REUSEADDR 1)
+    (bind sock AF_UNIX path)
+    sock))
+
+(define call-with-sigint
+  (if (not (provided? 'posix))
+      (lambda (thunk) (thunk))
+      (lambda (thunk)
+        (let ((handler #f))
+          (dynamic-wind
+            (lambda ()
+              (set! handler
+                    (sigaction SIGINT (lambda (sig) (throw 'interrupt)))))
+            thunk
+            (lambda ()
+              (if handler
+                  ;; restore Scheme handler, SIG_IGN or SIG_DFL.
+                  (sigaction SIGINT (car handler) (cdr handler))
+                  ;; restore original C handler.
+                  (sigaction SIGINT #f))))))))
+
+(define* (run-server #:optional (server-socket (make-tcp-server-socket)))
+  (define (accept-new-client)
+    (catch #t
+      (lambda () (call-with-sigint (lambda () (accept server-socket))))
+      (lambda (k . args)
+        (cond
+         ((port-closed? server-socket)
+          ;; Shutting down.
+          #f)
+         ((eq? k 'interrupt)
+          ;; Interrupt.
+          (close-socket! server-socket)
+          #f)
+         (else
+          (warn "Error accepting client" k args)
+          ;; Retry after a timeout.
+          (sleep 1)
+          (accept-new-client))))))
+  
+  (add-open-socket! server-socket)
+  (listen server-socket 5)
+  (let lp ((client (accept-new-client)))
+    ;; If client is false, we are shutting down.
+    (if client
+        (let ((client-socket (car client))
+              (client-addr (cdr client)))
+          (add-open-socket! client-socket)
+          (make-thread serve-client client-socket client-addr)
+          (lp (accept-new-client))))))
+
+(define* (spawn-server #:optional (server-socket (make-tcp-server-socket)))
+  (make-thread run-server server-socket))
+
+(define (serve-client client addr)
+  (with-continuation-barrier
+   (lambda ()
+     (with-input-from-port client
+       (lambda ()
+         (with-output-to-port client
+           (lambda ()
+             (with-error-to-port client
+               (lambda ()
+                 (with-fluids ((*repl-stack* '()))
+                   (start-repl))))))))))
+  (close-socket! client))


hooks/post-receive
-- 
GNU Guile



reply via email to

[Prev in Thread] Current Thread [Next in Thread]