guile-commits
[Top][All Lists]
Advanced

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

[Guile-commits] 01/01: Elide syscalls in fdes->port


From: Andy Wingo
Subject: [Guile-commits] 01/01: Elide syscalls in fdes->port
Date: Tue, 14 Feb 2017 16:03:50 -0500 (EST)

wingo pushed a commit to branch master
in repository guile.

commit 69ca2bb2217303b2556b131f3995ca4f6af81234
Author: Andy Wingo <address@hidden>
Date:   Tue Feb 14 21:57:35 2017 +0100

    Elide syscalls in fdes->port
    
    * libguile/fports.h (scm_t_fport): Add options field.
      (SCM_FDES_RANDOM_P): Deprecate.
      (scm_i_fdes_to_port): Add options argument.
    * libguile/fports.c (scm_i_fdes_to_port): Add options argument.  Only
      verify FD if SCM_FPORT_OPTION_VERIFY is there.
      (scm_fdes_to_port, scm_open_file_with_encoding): Adapt to
      scm_i_fdes_to_port changes.
      (fport_random_access_p): Don't try to seek if NOT_SEEKABLE option is
      set.
    * libguile/deprecated.h:
    * libguile/deprecated.c (SCM_FDES_RANDOM_P): Deprecate.
    * NEWS: Add deprecation.
    * libguile/filesys.c:
    * libguile/ioext.c:
    * libguile/posix.c:
    * libguile/read.c:
    * libguile/socket.c: Adapt callers.
---
 NEWS                  | 11 ++++++++++
 libguile/deprecated.c | 14 +++++++++++++
 libguile/deprecated.h |  4 ++++
 libguile/filesys.c    |  2 +-
 libguile/fports.c     | 56 +++++++++++++++++++++++++++++++++------------------
 libguile/fports.h     | 29 +++++++++++++++++---------
 libguile/ioext.c      |  3 ++-
 libguile/posix.c      | 14 +++++++++----
 libguile/read.c       | 16 ++++++---------
 libguile/socket.c     | 14 +++++++++----
 10 files changed, 114 insertions(+), 49 deletions(-)

diff --git a/NEWS b/NEWS
index 5680a20..46b09b9 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,17 @@ Please send Guile bug reports to address@hidden
 
 
 
+Changes in 2.1.7 (changes since the 2.1.6 alpha release):
+
+* New deprecations
+
+** `SCM_FDES_RANDOM_P'
+
+Instead, use `lseek (fd, 0, SEEK_CUR)' directly.
+
+* FIXME fold in 2.1.6 changes to main NEWS
+
+
 Changes in 2.1.6 (changes since the 2.1.5 alpha release):
 
 * New interfaces
diff --git a/libguile/deprecated.c b/libguile/deprecated.c
index c3d4935..cee6b1d 100644
--- a/libguile/deprecated.c
+++ b/libguile/deprecated.c
@@ -26,6 +26,9 @@
 
 #define SCM_BUILDING_DEPRECATED_CODE
 
+#include <sys/types.h>
+#include <unistd.h>
+
 #include "libguile/_scm.h"
 #include "libguile/deprecation.h"
 
@@ -940,6 +943,17 @@ scm_make_dynamic_state (SCM parent)
 
 
 
+int
+SCM_FDES_RANDOM_P (int fdes)
+{
+  scm_c_issue_deprecation_warning
+    ("SCM_FDES_RANDOM_P is deprecated.  Use lseek (fd, 0, SEEK_CUR).");
+
+  return (lseek (fdes, 0, SEEK_CUR) == -1) ? 0 : 1;
+}
+
+
+
 void
 scm_i_init_deprecated ()
 {
diff --git a/libguile/deprecated.h b/libguile/deprecated.h
index b1e455a..2c49076 100644
--- a/libguile/deprecated.h
+++ b/libguile/deprecated.h
@@ -270,6 +270,10 @@ SCM_DEPRECATED SCM scm_from_contiguous_array (SCM bounds, 
const SCM *elts,
 
 
 
+SCM_DEPRECATED int SCM_FDES_RANDOM_P (int fdes);
+
+
+
 void scm_i_init_deprecated (void);
 
 #endif
diff --git a/libguile/filesys.c b/libguile/filesys.c
index 9f665c1..40d5a41 100644
--- a/libguile/filesys.c
+++ b/libguile/filesys.c
@@ -1509,7 +1509,7 @@ SCM_DEFINE (scm_i_mkstemp, "mkstemp!", 1, 1, 0,
 
   scm_dynwind_end ();
 
-  port = scm_i_fdes_to_port (rv, mode_bits, tmpl);
+  port = scm_i_fdes_to_port (rv, mode_bits, tmpl, 0);
   if (is_binary)
     /* Use the binary-friendly ISO-8859-1 encoding. */
     scm_i_set_port_encoding_x (port, NULL);
diff --git a/libguile/fports.c b/libguile/fports.c
index 8fa6993..f79b4a3 100644
--- a/libguile/fports.c
+++ b/libguile/fports.c
@@ -264,7 +264,8 @@ scm_open_file_with_encoding (SCM filename, SCM mode,
   /* Create a port from this file descriptor.  The port's encoding is initially
      %default-port-encoding.  */
   port = scm_i_fdes_to_port (fdes, scm_i_mode_bits (mode),
-                             fport_canonicalize_filename (filename));
+                             fport_canonicalize_filename (filename),
+                             0);
 
   if (binary)
     {
@@ -391,35 +392,41 @@ SCM_DEFINE (scm_i_open_file, "open-file", 2, 0, 1,
    NAME is a string to be used as the port's filename.
 */
 SCM
-scm_i_fdes_to_port (int fdes, long mode_bits, SCM name)
+scm_i_fdes_to_port (int fdes, long mode_bits, SCM name, unsigned options)
 #define FUNC_NAME "scm_fdes_to_port"
 {
   SCM port;
   scm_t_fport *fp;
 
-  /* Test that fdes is valid.  */
-#ifdef F_GETFL
-  int flags = fcntl (fdes, F_GETFL, 0);
-  if (flags == -1)
-    SCM_SYSERROR;
-  flags &= O_ACCMODE;
-  if (flags != O_RDWR
-      && ((flags != O_WRONLY && (mode_bits & SCM_WRTNG))
-         || (flags != O_RDONLY && (mode_bits & SCM_RDNG))))
+  if (options & SCM_FPORT_OPTION_VERIFY)
     {
-      SCM_MISC_ERROR ("requested file mode not available on fdes", SCM_EOL);
-    }
+      /* Check that the foreign FD is valid and matches the mode
+         bits.  */
+#ifdef F_GETFL
+      int flags = fcntl (fdes, F_GETFL, 0);
+      if (flags == -1)
+        SCM_SYSERROR;
+      flags &= O_ACCMODE;
+      if (flags != O_RDWR
+          && ((flags != O_WRONLY && (mode_bits & SCM_WRTNG))
+              || (flags != O_RDONLY && (mode_bits & SCM_RDNG))))
+        {
+          SCM_MISC_ERROR ("requested file mode not available on fdes",
+                          SCM_EOL);
+        }
 #else
-  /* If we don't have F_GETFL, as on mingw, at least we can test that
-     it is a valid file descriptor.  */
-  struct stat st;
-  if (fstat (fdes, &st) != 0)
-    SCM_SYSERROR;
+      /* If we don't have F_GETFL, as on mingw, at least we can test that
+         it is a valid file descriptor.  */
+      struct stat st;
+      if (fstat (fdes, &st) != 0)
+        SCM_SYSERROR;
 #endif
+    }
 
   fp = (scm_t_fport *) scm_gc_malloc_pointerless (sizeof (scm_t_fport),
                                                   "file port");
   fp->fdes = fdes;
+  fp->options = options;
 
   port = scm_c_make_port (scm_file_port_type, mode_bits, (scm_t_bits)fp);
   
@@ -432,7 +439,8 @@ scm_i_fdes_to_port (int fdes, long mode_bits, SCM name)
 SCM
 scm_fdes_to_port (int fdes, char *mode, SCM name)
 {
-  return scm_i_fdes_to_port (fdes, scm_mode_bits (mode), name);
+  return scm_i_fdes_to_port (fdes, scm_mode_bits (mode), name,
+                             SCM_FPORT_OPTION_VERIFY);
 }
 
 /* Return a lower bound on the number of bytes available for input.  */
@@ -669,7 +677,15 @@ fport_close (SCM port)
 static int
 fport_random_access_p (SCM port)
 {
-  return SCM_FDES_RANDOM_P (SCM_FSTREAM (port)->fdes);
+  scm_t_fport *fp = SCM_FSTREAM (port);
+
+  if (fp->options & SCM_FPORT_OPTION_NOT_SEEKABLE)
+    return 0;
+
+  if (lseek (fp->fdes, 0, SEEK_CUR) == -1)
+    return 0;
+
+  return 1;
 }
 
 static int
diff --git a/libguile/fports.h b/libguile/fports.h
index ee9bf7c..afb8ba7 100644
--- a/libguile/fports.h
+++ b/libguile/fports.h
@@ -31,10 +31,13 @@
 
 /* struct allocated for each buffered FPORT.  */
 typedef struct scm_t_fport {
-  int fdes;                    /* file descriptor.  */
-  int revealed;                        /* 0 not revealed, > 1 revealed.
-                                * Revealed ports do not get GC'd.
-                                */
+  /* The file descriptor.  */
+  int fdes;
+  /* Revealed count; 0 indicates not revealed, > 1 revealed. Revealed
+     ports do not get garbage-collected.  */
+  int revealed;
+  /* Set of scm_fport_option flags.  */
+  unsigned options;
 } scm_t_fport;
 
 SCM_API scm_t_port_type *scm_file_port_type;
@@ -48,9 +51,6 @@ SCM_API scm_t_port_type *scm_file_port_type;
 #define SCM_OPINFPORTP(x) (SCM_OPFPORTP (x) && (SCM_CELL_WORD_0 (x) & 
SCM_RDNG))
 #define SCM_OPOUTFPORTP(x) (SCM_OPFPORTP (x) && (SCM_CELL_WORD_0 (x) & 
SCM_WRTNG))
 
-/* test whether fdes supports random access.  */
-#define SCM_FDES_RANDOM_P(fdes) ((lseek (fdes, 0, SEEK_CUR) == -1) ? 0 : 1)
-
 
 SCM_API void scm_evict_ports (int fd);
 SCM_INTERNAL int scm_i_mode_to_open_flags (SCM mode, int *is_binary,
@@ -74,8 +74,19 @@ SCM_INTERNAL void scm_init_fports (void);
 
 /* internal functions */
 
-SCM_INTERNAL SCM scm_i_fdes_to_port (int fdes, long mode_bits, SCM name);
-
+#ifdef BUILDING_LIBGUILE
+enum scm_fport_option
+  {
+    /* FD's that aren't created by Guile probably need to be checked for
+       validity.  We also check that the open mode is valid.  */
+    SCM_FPORT_OPTION_VERIFY = 1U<<0,
+    /* We know some ports aren't seekable and can elide a syscall in
+       that case.  */
+    SCM_FPORT_OPTION_NOT_SEEKABLE = 1U<<1
+  };
+SCM_INTERNAL SCM scm_i_fdes_to_port (int fdes, long mode_bits, SCM name,
+                                     unsigned options);
+#endif /* BUILDING_LIBGUILE */
 
 #endif  /* SCM_FPORTS_H */
 
diff --git a/libguile/ioext.c b/libguile/ioext.c
index 43c915a..4038fd5 100644
--- a/libguile/ioext.c
+++ b/libguile/ioext.c
@@ -226,7 +226,8 @@ SCM_DEFINE (scm_fdopen, "fdopen", 2, 0, 0,
 #define FUNC_NAME s_scm_fdopen
 {
   return scm_i_fdes_to_port (scm_to_int (fdes),
-                            scm_i_mode_bits (modes), SCM_BOOL_F);
+                            scm_i_mode_bits (modes), SCM_BOOL_F,
+                             SCM_FPORT_OPTION_VERIFY);
 }
 #undef FUNC_NAME
 
diff --git a/libguile/posix.c b/libguile/posix.c
index 495bfbb..686b801 100644
--- a/libguile/posix.c
+++ b/libguile/posix.c
@@ -242,8 +242,10 @@ SCM_DEFINE (scm_pipe, "pipe", 0, 0, 0,
   if (rv)
     SCM_SYSERROR;
   
-  p_rd = scm_fdes_to_port (fd[0], "r", sym_read_pipe);
-  p_wt = scm_fdes_to_port (fd[1], "w", sym_write_pipe);
+  p_rd = scm_i_fdes_to_port (fd[0], scm_mode_bits ("r"), sym_read_pipe,
+                             SCM_FPORT_OPTION_NOT_SEEKABLE);
+  p_wt = scm_i_fdes_to_port (fd[1], scm_mode_bits ("w"), sym_write_pipe,
+                             SCM_FPORT_OPTION_NOT_SEEKABLE);
   return scm_cons (p_rd, p_wt);
 }
 #undef FUNC_NAME
@@ -1418,12 +1420,16 @@ scm_open_process (SCM mode, SCM prog, SCM args)
   if (reading)
     {
       close (c2p[1]);
-      read_port = scm_fdes_to_port (c2p[0], "r0", sym_read_pipe);
+      read_port = scm_i_fdes_to_port (c2p[0], scm_mode_bits ("r0"),
+                                      sym_read_pipe,
+                                      SCM_FPORT_OPTION_NOT_SEEKABLE);
     }
   if (writing)
     {
       close (p2c[0]);
-      write_port = scm_fdes_to_port (p2c[1], "w0", sym_write_pipe);
+      write_port = scm_i_fdes_to_port (p2c[1], scm_mode_bits ("w0"),
+                                       sym_write_pipe,
+                                       SCM_FPORT_OPTION_NOT_SEEKABLE);
     }
 
   return scm_values (scm_list_3 (read_port,
diff --git a/libguile/read.c b/libguile/read.c
index 5c436e2..085cdb9 100644
--- a/libguile/read.c
+++ b/libguile/read.c
@@ -2105,21 +2105,17 @@ scm_i_scan_for_encoding (SCM port)
       memcpy (header, scm_port_buffer_take_pointer (buf, cur), bytes_read);
       header[bytes_read] = '\0';
     }
-  else
+  else if (pt->rw_random)
     {
-      /* Try to read some bytes and then seek back.  Not all ports
-         support seeking back; and indeed some file ports (like
-         /dev/urandom) will succeed on an lseek (fd, 0, SEEK_CUR)---the
-         check performed by SCM_FPORT_FDES---but fail to seek
-         backwards.  Hence this block comes second.  We prefer to use
-         the read buffer in-place.  */
-      if (SCM_FPORTP (port) && !SCM_FDES_RANDOM_P (SCM_FPORT_FDES (port)))
-        return NULL;
-
+      /* The port is seekable.  This is OK but grubbing in the read
+         buffer is better, so this case is just a fallback.  */
       bytes_read = scm_c_read (port, header, SCM_ENCODING_SEARCH_SIZE);
       header[bytes_read] = '\0';
       scm_seek (port, scm_from_int (0), scm_from_int (SEEK_SET));
     }
+  else
+    /* No input available and not seekable; scan fails.  */
+    return NULL;
 
   /* search past "coding[:=]" */
   pos = header;
diff --git a/libguile/socket.c b/libguile/socket.c
index 37e9f52..4f2acff 100644
--- a/libguile/socket.c
+++ b/libguile/socket.c
@@ -367,7 +367,12 @@ SCM_DEFINE (scm_inet_pton, "inet-pton", 2, 0, 0,
 
 SCM_SYMBOL (sym_socket, "socket");
 
-#define SCM_SOCK_FD_TO_PORT(fd) scm_fdes_to_port (fd, "r+0", sym_socket)
+static SCM
+scm_socket_fd_to_port (int fd)
+{
+  return scm_i_fdes_to_port (fd, scm_mode_bits ("r+0"), sym_socket,
+                             SCM_FPORT_OPTION_NOT_SEEKABLE);
+}
 
 SCM_DEFINE (scm_socket, "socket", 3, 0, 0,
             (SCM family, SCM style, SCM proto),
@@ -391,7 +396,7 @@ SCM_DEFINE (scm_socket, "socket", 3, 0, 0,
               scm_to_int (proto));
   if (fd == -1)
     SCM_SYSERROR;
-  return SCM_SOCK_FD_TO_PORT (fd);
+  return scm_socket_fd_to_port (fd);
 }
 #undef FUNC_NAME
 
@@ -413,7 +418,8 @@ SCM_DEFINE (scm_socketpair, "socketpair", 3, 0, 0,
   if (socketpair (fam, scm_to_int (style), scm_to_int (proto), fd) == -1)
     SCM_SYSERROR;
 
-  return scm_cons (SCM_SOCK_FD_TO_PORT (fd[0]), SCM_SOCK_FD_TO_PORT (fd[1]));
+  return scm_cons (scm_socket_fd_to_port (fd[0]),
+                   scm_socket_fd_to_port (fd[1]));
 }
 #undef FUNC_NAME
 #endif
@@ -1269,7 +1275,7 @@ SCM_DEFINE (scm_accept, "accept", 1, 0, 0,
         return SCM_BOOL_F;
       SCM_SYSERROR;
     }
-  newsock = SCM_SOCK_FD_TO_PORT (newfd);
+  newsock = scm_socket_fd_to_port (newfd);
   address = _scm_from_sockaddr (&addr, addr_size,
                                FUNC_NAME);
 



reply via email to

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