guile-devel
[Top][All Lists]
Advanced

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

[PATCH] nonblocking write/recv/send/connect/accept


From: Christopher Cramer
Subject: [PATCH] nonblocking write/recv/send/connect/accept
Date: Wed, 27 Mar 2002 13:03:51 -0600
User-agent: Mutt/1.2.5i

Here it is. scm_connect was a little tricky and it actually looks very
ugly to me, but the connect system call was really not designed for this
sort of thing =^(.

It's a patch for stable, but I suspect it changes too much to actually
make it into stable. It applies to unstable without any problems though.

        * fports.c (scm_fdes_wait_for_input): raise exception if
        scm_internal_select fails.

        * fports.c (write_all, fport_flush), socket.c (scm_connect,
        scm_accept, scm_recv, scm_send): call scm_internal_select,
        to keep from from blocking other cooperative threads.

Index: libguile/fports.c
===================================================================
RCS file: /cvsroot/guile/guile/guile-core/libguile/fports.c,v
retrieving revision 1.100.2.4
diff -u -r1.100.2.4 fports.c
--- libguile/fports.c   14 Mar 2002 05:26:15 -0000      1.100.2.4
+++ libguile/fports.c   27 Mar 2002 18:38:00 -0000
@@ -537,13 +537,16 @@
       if (flags == -1)
        scm_syserror ("scm_fdes_wait_for_input");
       if (!(flags & O_NONBLOCK))
-       do
-         {
-           FD_ZERO (&readfds);
-           FD_SET (fdes, &readfds);
-           n = scm_internal_select (fdes + 1, &readfds, NULL, NULL, NULL);
-         }
-       while (n == -1 && errno == EINTR);
+       {
+         do
+           {
+             FD_ZERO (&readfds);
+             FD_SET (fdes, &readfds);
+             n = scm_internal_select (fdes + 1, &readfds, NULL, NULL, NULL);
+           }
+         while (n == -1 && errno == EINTR);
+         if (n == -1) scm_syserror ("scm_fdes_wait_for_input");
+       }
     }
 }
 #endif
@@ -647,6 +650,28 @@
     {
       size_t done;
 
+#ifdef GUILE_ISELECT
+      {
+       int n;
+       SELECT_TYPE writefds;
+       int flags = fcntl (fdes, F_GETFL);
+
+       if (flags == -1)
+         scm_syserror ("write_all");
+       if (!(flags & O_NONBLOCK))
+         {
+           do
+             {
+               FD_ZERO (&writefds);
+               FD_SET (fdes, &writefds);
+               n = scm_internal_select (fdes + 1, NULL, &writefds, NULL, NULL);
+             }
+           while (n == -1 && errno == EINTR);
+           if (n == -1) scm_syserror ("write_all");
+         }
+      }
+#endif /* GUILE_ISELECT */
+
       SCM_SYSCALL (done = write (fdes, data, remaining));
 
       if (done == -1)
@@ -727,12 +752,35 @@
   unsigned char *ptr = pt->write_buf;
   long init_size = pt->write_pos - pt->write_buf;
   long remaining = init_size;
+  int fd = fp->fdes;
 
   while (remaining > 0)
     {
       long count;
 
-      SCM_SYSCALL (count = write (fp->fdes, ptr, remaining));
+#ifdef GUILE_ISELECT
+      {
+       int n;
+       SELECT_TYPE writefds;
+       int flags = fcntl (fd, F_GETFL);
+
+       if (flags == -1)
+         scm_syserror ("fport_flush");
+       if (!(flags & O_NONBLOCK))
+         {
+           do
+             {
+               FD_ZERO (&writefds);
+               FD_SET (fd, &writefds);
+               n = scm_internal_select (fd + 1, NULL, &writefds, NULL, NULL);
+             }
+           while (n == -1 && errno == EINTR);
+           if (n == -1) scm_syserror ("fport_flush");
+         }
+      }
+#endif /* GUILE_ISELECT */
+
+      SCM_SYSCALL (count = write (fd, ptr, remaining));
       if (count < 0)
        {
          /* error.  assume nothing was written this call, but
@@ -755,7 +803,7 @@
              char buf[11];
 
              write (2, msg, strlen (msg));
-             sprintf (buf, "%d\n", fp->fdes);
+             sprintf (buf, "%d\n", fd);
              write (2, buf, strlen (buf));
 
              count = remaining;
Index: libguile/socket.c
===================================================================
RCS file: /cvsroot/guile/guile/guile-core/libguile/socket.c,v
retrieving revision 1.80.2.3
diff -u -r1.80.2.3 socket.c
--- libguile/socket.c   15 Mar 2002 09:23:19 -0000      1.80.2.3
+++ libguile/socket.c   27 Mar 2002 18:38:03 -0000
@@ -43,11 +43,13 @@
 
 
 #include <errno.h>
+#include <fcntl.h>
 
 #include "libguile/_scm.h"
 #include "libguile/unif.h"
 #include "libguile/feature.h"
 #include "libguile/fports.h"
+#include "libguile/iselect.h"
 #include "libguile/strings.h"
 #include "libguile/vectors.h"
 
@@ -809,6 +811,83 @@
            "The return value is unspecified.")
 #define FUNC_NAME s_scm_connect
 {
+#ifdef GUILE_ISELECT
+  int fd;
+  struct sockaddr *soka;
+  int size;
+  long flags;
+  int saved_errno;
+
+  sock = SCM_COERCE_OUTPORT (sock);
+  SCM_VALIDATE_OPFPORT (1,sock);
+  SCM_VALIDATE_INUM (2,fam);
+  fd = SCM_FPORT_FDES (sock);
+  soka = scm_fill_sockaddr (SCM_INUM (fam), address, &args, 3, FUNC_NAME,
+       &size);
+  if (-1 == (flags = fcntl(fd, F_GETFL))) SCM_SYSERROR;
+  if (!(flags & O_NONBLOCK))
+    {
+      int rc;
+       
+      if (fcntl (fd, F_SETFL, flags | O_NONBLOCK)) SCM_SYSERROR;
+      rc = connect (fd, soka, size);
+
+      if (rc && errno == EINPROGRESS)
+        {
+          SELECT_TYPE writefds;
+          socklen_t len;
+    
+          free (soka);
+          do
+           {
+             FD_ZERO (&writefds);
+             FD_SET (fd, &writefds);
+             rc = scm_internal_select(fd + 1, NULL, &writefds,
+                     NULL, NULL);
+            }
+         while (rc == -1 && errno == EINTR);
+         saved_errno = errno;
+          if (fcntl (fd, F_SETFL, flags)) SCM_SYSERROR;
+          if (rc == -1)
+           {
+             errno = saved_errno;
+             SCM_SYSERROR;
+           }
+  
+          len = sizeof (rc);
+          if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &rc, &len)) SCM_SYSERROR;
+          if (rc)
+            {
+              errno = rc;
+             SCM_SYSERROR;
+           }
+        }
+      else if (rc)
+        {
+          saved_errno = errno;
+          free (soka);
+          if (fcntl (fd, F_SETFL, flags)) SCM_SYSERROR;
+          errno = saved_errno;
+          SCM_SYSERROR;
+        }
+      else
+        {
+          free (soka);
+          if (fcntl (fd, F_SETFL, flags)) SCM_SYSERROR;
+        }
+    }
+  else
+    {
+      if (connect (fd, soka, size))
+       {
+         saved_errno = errno;
+         free (soka);
+         errno = saved_errno;
+         SCM_SYSERROR;
+       }
+    }
+  return SCM_UNSPECIFIED;
+#else /* GUILE_ISELECT */
   int fd;
   struct sockaddr *soka;
   int size;
@@ -822,13 +901,15 @@
   if (connect (fd, soka, size) == -1)
     {
       int save_errno = errno;
-      
+
       free (soka);
       errno = save_errno;
       SCM_SYSERROR;
     }
+
   free (soka);
   return SCM_UNSPECIFIED;
+#endif /* GUILE_ISELECT */
 }
 #undef FUNC_NAME
 
@@ -1019,6 +1100,29 @@
   sock = SCM_COERCE_OUTPORT (sock);
   SCM_VALIDATE_OPFPORT (1, sock);
   fd = SCM_FPORT_FDES (sock);
+
+#ifdef GUILE_ISELECT
+  {
+    int n;
+    SELECT_TYPE readfds;
+    int flags = fcntl (fd, F_GETFL);
+
+    if (flags == -1)
+      scm_syserror ("scm_accept");
+    if (!(flags & O_NONBLOCK))
+      {
+        do
+         {
+           FD_ZERO (&readfds);
+           FD_SET (fd, &readfds);
+           n = scm_internal_select (fd + 1, &readfds, NULL, NULL, NULL);
+         }
+        while (n == -1 && errno == EINTR);
+        if (n == -1) scm_syserror ("scm_accept");
+      }
+  }
+#endif /* GUILE_ISELECT */
+
   newfd = accept (fd, addr, &addr_size);
   if (newfd == -1)
     SCM_SYSERROR;
@@ -1101,6 +1205,28 @@
   SCM_VALIDATE_INUM_DEF_COPY (3,flags,0,flg);
   fd = SCM_FPORT_FDES (sock);
 
+#ifdef GUILE_ISELECT
+  {
+    int n;
+    SELECT_TYPE readfds;
+    int flags = fcntl (fd, F_GETFL);
+
+    if (flags == -1)
+      scm_syserror ("scm_recv");
+    if (!(flags & O_NONBLOCK))
+      {
+        do
+         {
+           FD_ZERO (&readfds);
+           FD_SET (fd, &readfds);
+           n = scm_internal_select (fd + 1, &readfds, NULL, NULL, NULL);
+         }
+        while (n == -1 && errno == EINTR);
+        if (n == -1) scm_syserror ("scm_recv");
+      }
+  }
+#endif /* GUILE_ISELECT */
+
   SCM_SYSCALL (rv = recv (fd, SCM_STRING_CHARS (buf), SCM_STRING_LENGTH (buf), 
flg));
   if (rv == -1)
     SCM_SYSERROR;
@@ -1134,6 +1260,28 @@
   SCM_VALIDATE_STRING (2, message);
   SCM_VALIDATE_INUM_DEF_COPY (3,flags,0,flg);
   fd = SCM_FPORT_FDES (sock);
+
+#ifdef GUILE_ISELECT
+  {
+    int n;
+    SELECT_TYPE writefds;
+    int flags = fcntl (fd, F_GETFL);
+
+    if (flags == -1)
+      scm_syserror ("scm_send");
+    if (!(flags & O_NONBLOCK))
+      {
+        do
+         {
+           FD_ZERO (&writefds);
+           FD_SET (fd, &writefds);
+           n = scm_internal_select (fd + 1, NULL, &writefds, NULL, NULL);
+         }
+        while (n == -1 && errno == EINTR);
+        if (n == -1) scm_syserror ("scm_send");
+      }
+  }
+#endif /* GUILE_ISELECT */
 
   SCM_SYSCALL (rv = send (fd, SCM_STRING_CHARS (message), SCM_STRING_LENGTH 
(message), flg));
   if (rv == -1)

-- 
Christopher Cramer <address@hidden> <http://www.pyro.net/~crayc/>
Quoi que vous fassiez, écrasez l'infâme, et aimez qui vous aime.
        -- Voltaire



reply via email to

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