guile-devel
[Top][All Lists]
Advanced

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

Re: Unbuffered socket I/O


From: Ludovic Courtès
Subject: Re: Unbuffered socket I/O
Date: Mon, 26 Feb 2007 15:07:43 +0100
User-agent: Gnus/5.110006 (No Gnus v0.6) Emacs/21.4 (gnu/linux)

Hi,

Kevin Ryde <address@hidden> writes:

> address@hidden (Ludovic Courtès) writes:

>>   #define SCM_SOCK_FD_TO_PORT(fd) \
>>      scm_fdes_to_port (fd, "r", sym_socket)
>
> That's an incompatible change, I think, since it can leave unflushed
> data where previously it went straight out.

Right.  That's an incompatible change if the _output_ is buffered.
Input can be buffered, though, without this being visible by users.

Fortunately, port buffering doesn't have to be symmetrical (although the
API allowing to do that is internal---actually, we might want to expose
and document `scm_fport_buffer_add ()').  Thus, I propose the following
change, where sockets are turned into ports whose output is left
unbuffered and whose input is buffered.  Again, this has no visible
effect on user programs AFAICS.

I tried it with TCP server-side sockets and the performance impact is
_huge_.  Actually, it seems even hard to write a TCP server without this
because it takes so long to read a single octet that clients may
time-out before the server is done receiving their request! (I observed
this with RPC server/clients)

BTW, do you know what the purpose of `fport_wait_for_input ()' is?  It
does nothing for O_NONBLOCK streams and waits for events otherwise.
Since, for blocking streams, `read ()' does not return until either EOF
is reached or at least one octet was read, `fport_wait_for_input ()'
seems redundant.

Thanks,
Ludovic.


--- orig/libguile/fports.c
+++ mod/libguile/fports.c
@@ -90,11 +90,11 @@
 /* default buffer size, used if the O/S won't supply a value.  */
 static const size_t default_buffer_size = 1024;
 
-/* create FPORT buffer with specified sizes (or -1 to use default size or
-   0 for no buffer.  */
-static void
-scm_fport_buffer_add (SCM port, long read_size, int write_size)
-#define FUNC_NAME "scm_fport_buffer_add"
+/* Create FPORT buffer with specified sizes (or -1 to use default size or
+   0 for no buffer).  */
+void
+scm_i_fport_buffer_add (SCM port, long read_size, long write_size)
+#define FUNC_NAME "scm_i_fport_buffer_add"
 {
   scm_t_port *pt = SCM_PTAB_ENTRY (port);
 
@@ -212,7 +212,7 @@
   if (pt->write_buf != &pt->shortbuf)
     scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer");
 
-  scm_fport_buffer_add (port, csize, csize);
+  scm_i_fport_buffer_add (port, csize, csize);
   return SCM_UNSPECIFIED;
 }
 #undef FUNC_NAME
@@ -465,9 +465,9 @@
     pt->rw_random = SCM_FDES_RANDOM_P (fdes);
     SCM_SETSTREAM (port, fp);
     if (mode_bits & SCM_BUF0)
-      scm_fport_buffer_add (port, 0, 0);
+      scm_i_fport_buffer_add (port, 0, 0);
     else
-      scm_fport_buffer_add (port, -1, -1);
+      scm_i_fport_buffer_add (port, -1, -1);
   }
   SCM_SET_FILENAME (port, name);
   scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);


--- orig/libguile/fports.h
+++ mod/libguile/fports.h
@@ -60,7 +60,8 @@
 SCM_API SCM scm_i_fdes_to_port (int fdes, long mode_bits, SCM name);
 SCM_API int scm_i_fport_truncate (SCM, SCM);
 SCM_API SCM scm_i_fport_seek (SCM, SCM, int);
-
+SCM_API void scm_i_fport_buffer_add (SCM port, long read_size,
+                                    long write_size);
 
 #endif  /* SCM_FPORTS_H */
 


--- orig/libguile/socket.c
+++ mod/libguile/socket.c
@@ -403,9 +403,26 @@
 
 #endif  /* HAVE_IPV6 */
 
+
+/* Sockets.  */
+
 SCM_SYMBOL (sym_socket, "socket");
 
-#define SCM_SOCK_FD_TO_PORT(fd) scm_fdes_to_port (fd, "r+0", sym_socket)
+/* Size of the input buffer of socket ports.  */
+#define SCM_SOCKET_INPUT_BUFFER_SIZE  4096
+
+
+/* Return a socket with buffered input and unbufferred output.  */
+static inline SCM
+socket_to_port (int fd)
+{
+  SCM port;
+
+  port = scm_fdes_to_port (fd, "r+0", sym_socket);
+  scm_i_fport_buffer_add (port, SCM_SOCKET_INPUT_BUFFER_SIZE, 0);
+
+  return port;
+}
 
 SCM_DEFINE (scm_socket, "socket", 3, 0, 0,
             (SCM family, SCM style, SCM proto),
@@ -429,7 +446,7 @@
               scm_to_int (proto));
   if (fd == -1)
     SCM_SYSERROR;
-  return SCM_SOCK_FD_TO_PORT (fd);
+  return socket_to_port (fd);
 }
 #undef FUNC_NAME
 
@@ -451,7 +468,7 @@
   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 (socket_to_port (fd[0]), socket_to_port (fd[1]));
 }
 #undef FUNC_NAME
 #endif
@@ -1312,7 +1329,7 @@
   newfd = accept (fd, addr, &addr_size);
   if (newfd == -1)
     SCM_SYSERROR;
-  newsock = SCM_SOCK_FD_TO_PORT (newfd);
+  newsock = socket_to_port (newfd);
   address = _scm_from_sockaddr (addr, addr_size, FUNC_NAME);
   return scm_cons (newsock, address);
 }




reply via email to

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