gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] r34553 - in gnunet/src: include util


From: gnunet
Subject: [GNUnet-SVN] r34553 - in gnunet/src: include util
Date: Sun, 14 Dec 2014 15:54:54 +0100

Author: LRN
Date: 2014-12-14 15:54:54 +0100 (Sun, 14 Dec 2014)
New Revision: 34553

Modified:
   gnunet/src/include/gnunet_network_lib.h
   gnunet/src/util/network.c
Log:
Grothoff's W32 select slist elimination and prettification

Modified: gnunet/src/include/gnunet_network_lib.h
===================================================================
--- gnunet/src/include/gnunet_network_lib.h     2014-12-14 14:54:50 UTC (rev 
34552)
+++ gnunet/src/include/gnunet_network_lib.h     2014-12-14 14:54:54 UTC (rev 
34553)
@@ -59,9 +59,23 @@
 
 #ifdef WINDOWS
   /**
-   * Linked list of handles
+   * Array of file handles (from pipes) that are also in
+   * the FDSet.  Needed as those cannot go into @e sds
+   * on W32.
    */
-  struct GNUNET_CONTAINER_SList *handles;
+  const struct GNUNET_DISK_FileHandle **handles;
+
+  /**
+   * Size of the @e handles array
+   */
+  unsigned int handles_size;
+
+  /**
+   * Number of @e handles slots in use. Always
+   * smaller than @e handles_size.
+   */
+  unsigned int handles_pos;
+
 #endif
 
 };

Modified: gnunet/src/util/network.c
===================================================================
--- gnunet/src/util/network.c   2014-12-14 14:54:50 UTC (rev 34552)
+++ gnunet/src/util/network.c   2014-12-14 14:54:54 UTC (rev 34553)
@@ -1039,7 +1039,7 @@
   FD_ZERO (&fds->sds);
   fds->nsds = 0;
 #ifdef MINGW
-  GNUNET_CONTAINER_slist_clear (fds->handles);
+  fds->handles_pos = 0;
 #endif
 }
 
@@ -1092,25 +1092,33 @@
 
   for (nfds = src->nsds; nfds >= 0; nfds--)
     if (FD_ISSET (nfds, &src->sds))
-
-    {
       FD_SET (nfds, &dst->sds);
-      if (nfds + 1 > dst->nsds)
-        dst->nsds = nfds + 1;
-    }
+  dst->nsds = GNUNET_MAX (dst->nsds,
+                          src->nsds);
 #else
   /* This is MinGW32-specific implementation that relies on the code that
    * winsock2.h defines for FD_SET. Namely, it relies on FD_SET checking
    * that fd being added is not already in the set.
    * Also relies on us knowing what's inside fd_set (fd_count and fd_array).
+   *
+   * NOTE: I don't understand why the UNIX-logic wouldn't work
+   * for the first part here as well. -CG
    */
-  int i;
+  unsigned int i;
+
   for (i = 0; i < src->sds.fd_count; i++)
-    FD_SET (src->sds.fd_array[i], &dst->sds);
-  if (src->nsds > dst->nsds)
-    dst->nsds = src->nsds;
+    FD_SET (src->sds.fd_array[i],
+            &dst->sds);
+  dst->nsds = GNUNET_MAX (src->nsds,
+                          dst->nsds);
 
-  GNUNET_CONTAINER_slist_append (dst->handles, src->handles);
+  /* also copy over `struct GNUNET_DISK_FileHandle` array */
+  if (dst->handles_pos + src->handles_pos > dst->handles_size)
+    GNUNET_array_grow (dst->handles,
+                       dst->handles_size,
+                       ((dst->handles_pos + src->handles_pos) << 1));
+  for (i = 0; i < src->handles_pos; i++)
+    dst->handles[dst->handles_pos++] = src->handles[i];
 #endif
 }
 
@@ -1129,8 +1137,14 @@
            &to->sds);
   to->nsds = from->nsds;
 #ifdef MINGW
-  GNUNET_CONTAINER_slist_clear (to->handles);
-  GNUNET_CONTAINER_slist_append (to->handles, from->handles);
+  if (from->handles_pos > to->handles_size)
+    GNUNET_array_grow (to->handles,
+                       to->handles_size,
+                       from->handles_pos * 2);
+  memcpy (to->handles,
+          from->handles,
+          from->handles_pos * sizeof (struct GNUNET_NETWORK_Handle *));
+  to->handles_pos = from->handles_pos;
 #endif
 }
 
@@ -1237,10 +1251,11 @@
                                  const struct GNUNET_DISK_FileHandle *h)
 {
 #ifdef MINGW
-  GNUNET_CONTAINER_slist_add (fds->handles,
-                              GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, h,
-                              sizeof (struct GNUNET_DISK_FileHandle));
-
+  if (fds->handles_pos == fds->handles_size)
+    GNUNET_array_grow (fds->handles,
+                       fds->handles_size,
+                       fds->handles_size * 2 + 2);
+  fds->handles[fds->handles_pos++] = h;
 #else
   int fd;
 
@@ -1267,9 +1282,12 @@
                                    const struct GNUNET_DISK_FileHandle *h)
 {
 #ifdef MINGW
-  return GNUNET_CONTAINER_slist_contains (fds->handles, h,
-                                          sizeof (struct
-                                                  GNUNET_DISK_FileHandle));
+  unsigned int i;
+
+  for (i=0;i<fds->handles_pos;i++)
+    if (fds->handles[i] == h)
+      return GNUNET_YES;
+  return GNUNET_NO;
 #else
   return FD_ISSET (h->fd,
                    &fds->sds);
@@ -1277,7 +1295,29 @@
 }
 
 
+#ifdef MINGW
 /**
+ * Numerically compare pointers to sort them.
+ * Used to test for overlap in the arrays.
+ *
+ * @param p1 a pointer
+ * @param p2 a pointer
+ * @return -1, 0 or 1, if the p1 < p2, p1==p2 or p1 > p2.
+ */
+static int
+ptr_cmp (const void *p1,
+         const void *p2)
+{
+  if (p1 == p2)
+    return 0;
+  if ((intptr_t) p1 < (intptr_t) p2)
+    return -1;
+  return 1;
+}
+#endif
+
+
+/**
  * Checks if two fd sets overlap
  *
  * @param fds1 first fd set
@@ -1304,49 +1344,47 @@
   }
   return GNUNET_NO;
 #else
-  struct GNUNET_CONTAINER_SList_Iterator it;
-  struct GNUNET_DISK_FileHandle *h;
-  int i;
-  int j;
+  unsigned int i;
+  unsigned int j;
 
   /* This code is somewhat hacky, we are not supposed to know what's
    * inside of fd_set; also the O(n^2) is really bad... */
   for (i = 0; i < fds1->sds.fd_count; i++)
-  {
     for (j = 0; j < fds2->sds.fd_count; j++)
-    {
       if (fds1->sds.fd_array[i] == fds2->sds.fd_array[j])
         return GNUNET_YES;
-    }
-  }
-  it = GNUNET_CONTAINER_slist_begin (fds1->handles);
-  while (GNUNET_CONTAINER_slist_end (&it) != GNUNET_YES)
+
+  /* take a short cut if possible */
+  if ( (0 == fds1->handles_pos) ||
+       (0 == fds2->handles_pos) )
+    return GNUNET_NO;
+
+  /* Sort file handles array to avoid quadratic complexity when
+     checking for overlap */
+  qsort (fds1->handles,
+         fds1->handles_pos,
+         sizeof (void *),
+         &ptr_cmp);
+  qsort (fds2->handles,
+         fds2->handles_pos,
+         sizeof (void *),
+         &ptr_cmp);
+  i = 0;
+  j = 0;
+  while ( (i < fds1->handles_pos) &&
+          (j < fds2->handles_pos) )
   {
-#if DEBUG_NETWORK
-    struct GNUNET_CONTAINER_SList_Iterator t;
-#endif
-    h = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&it,
-                                                                      NULL);
-#if DEBUG_NETWORK
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Checking that FD 0x%x is in another set:\n",
-         h->h);
-    for (t = GNUNET_CONTAINER_slist_begin (fds2->handles);
-         GNUNET_CONTAINER_slist_end (&t) != GNUNET_YES;
-         GNUNET_CONTAINER_slist_next (&t))
+    switch (ptr_cmp (fds1->handles[i],
+                     fds2->handles[j]))
     {
-      struct GNUNET_DISK_FileHandle *fh;
-
-      fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&t,
-                                                                         NULL);
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "0x%x\n", fh->h);
-    }
-#endif
-    if (GNUNET_CONTAINER_slist_contains
-        (fds2->handles, h, sizeof (struct GNUNET_DISK_FileHandle)))
-    {
+    case -1:
+      i++;
+      break;
+    case 0:
       return GNUNET_YES;
+    case 1:
+      j++;
     }
-    GNUNET_CONTAINER_slist_next (&it);
   }
   return GNUNET_NO;
 #endif
@@ -1364,9 +1402,6 @@
   struct GNUNET_NETWORK_FDSet *fds;
 
   fds = GNUNET_new (struct GNUNET_NETWORK_FDSet);
-#ifdef MINGW
-  fds->handles = GNUNET_CONTAINER_slist_create ();
-#endif
   GNUNET_NETWORK_fdset_zero (fds);
   return fds;
 }
@@ -1381,7 +1416,9 @@
 GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds)
 {
 #ifdef MINGW
-  GNUNET_CONTAINER_slist_destroy (fds->handles);
+  GNUNET_array_grow (fds->handles,
+                     fds->handles_size,
+                     0);
 #endif
   GNUNET_free (fds);
 }
@@ -1464,6 +1501,105 @@
   }
   return 0;
 }
+
+
+static HANDLE hEventPipeWrite;
+
+static HANDLE hEventReadReady;
+
+static struct _select_params sp;
+
+static HANDLE select_thread;
+
+static HANDLE select_finished_event;
+
+static HANDLE select_standby_event;
+
+static SOCKET select_wakeup_socket = -1;
+
+static SOCKET select_send_socket = -1;
+
+static struct timeval select_timeout;
+
+
+/**
+ * On W32, we actually use a thread to help with the
+ * event loop due to W32-API limitations.  This function
+ * initializes that thread.
+ */
+static void
+initialize_select_thread ()
+{
+  SOCKET select_listening_socket = -1;
+  struct sockaddr_in s_in;
+  int alen;
+  int res;
+  unsigned long p;
+
+  select_standby_event = CreateEvent (NULL, TRUE, FALSE, NULL);
+  select_finished_event = CreateEvent (NULL, TRUE, FALSE, NULL);
+
+  select_wakeup_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+  select_listening_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+  p = 1;
+  res = ioctlsocket (select_wakeup_socket, FIONBIO, &p);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Select thread initialization: ioctlsocket() returns %d\n",
+       res);
+
+  alen = sizeof (s_in);
+  s_in.sin_family = AF_INET;
+  s_in.sin_port = 0;
+  s_in.sin_addr.S_un.S_un_b.s_b1 = 127;
+  s_in.sin_addr.S_un.S_un_b.s_b2 = 0;
+  s_in.sin_addr.S_un.S_un_b.s_b3 = 0;
+  s_in.sin_addr.S_un.S_un_b.s_b4 = 1;
+  res = bind (select_listening_socket,
+              (const struct sockaddr *) &s_in,
+              sizeof (s_in));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Select thread initialization: bind() returns %d\n",
+       res);
+
+  res = getsockname (select_listening_socket,
+                     (struct sockaddr *) &s_in,
+                     &alen);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Select thread initialization: getsockname() returns %d\n",
+       res);
+
+  res = listen (select_listening_socket,
+                SOMAXCONN);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Select thread initialization: listen() returns %d\n",
+       res);
+  res = connect (select_wakeup_socket,
+                 (const struct sockaddr *) &s_in,
+                 sizeof (s_in));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Select thread initialization: connect() returns %d\n",
+       res);
+
+  select_send_socket = accept (select_listening_socket,
+                               (struct sockaddr *) &s_in,
+                               &alen);
+
+  closesocket (select_listening_socket);
+
+  sp.wakeup = select_finished_event;
+  sp.standby = select_standby_event;
+  sp.wakeup_socket = select_wakeup_socket;
+
+  select_thread = CreateThread (NULL,
+                                0,
+                                _selector,
+                                &sp,
+                                0, NULL);
+}
+
+
 #endif
 
 
@@ -1522,6 +1658,87 @@
 
 
 /**
+ * Non-blocking test if a pipe is ready for reading.
+ *
+ * @param fh pipe handle
+ * @return #GNUNET_YES if the pipe is ready for reading
+ */
+static int
+pipe_read_ready (struct GNUNET_DISK_FileHandle *fh)
+{
+  DWORD error;
+  BOOL bret;
+  DWORD waitstatus = 0;
+
+  SetLastError (0);
+  bret = PeekNamedPipe (fh->h, NULL, 0, NULL, &waitstatus, NULL);
+  error = GetLastError ();
+  if (0 == bret)
+  {
+    /* TODO: either add more errors to this condition, or eliminate it
+     * entirely (failed to peek -> pipe is in serious trouble, should
+     * be selected as readable).
+     */
+    if ( (error != ERROR_BROKEN_PIPE) &&
+         (error != ERROR_INVALID_HANDLE) )
+      return GNUNET_NO;
+  }
+  else if (waitstatus <= 0)
+    return GNUNET_NO;
+  return GNUNET_YES;
+}
+
+
+/**
+ * Non-blocking test if a pipe is having an IO exception.
+ *
+ * @param fh pipe handle
+ * @return #GNUNET_YES if the pipe is having an IO exception.
+ */
+static int
+pipe_except_ready (struct GNUNET_DISK_FileHandle *fh)
+{
+  DWORD dwBytes;
+
+  if (PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL))
+    return GNUNET_NO;
+  return GNUNET_YES;
+}
+
+
+/**
+ * Iterate over handles in fds, destructively rewrite the
+ * handles array contents of fds so that it starts with the
+ * handles that are ready, and update handles_pos accordingly.
+ *
+ * @param fds set of handles (usually pipes) to be checked for readiness
+ * @param except GNUNET_NO if fds should be checked for readiness to read,
+ * GNUNET_YES if fds should be checked for exceptions
+ * (there is no way to check for write-readiness - pipes are always 
write-ready)
+ * @return number of ready handles
+ */
+static int
+check_handles_status (struct GNUNET_NETWORK_FDSet *fds, int except)
+{
+  struct GNUNET_DISK_FileHandle *fh;
+  unsigned int roff;
+  unsigned int woff;
+  int is_pipe;
+
+  for (woff = 0, roff = 0; roff < fds->handles_pos; roff++)
+  {
+    fh = fds->handles[roff];
+    is_pipe = fh->type == GNUNET_DISK_HANLDE_TYPE_PIPE;
+    if ((except && is_pipe && pipe_except_ready (fh)) ||
+        (!except && (!is_pipe || pipe_read_ready (fh))))
+      fds->handles[woff++] = fh;
+  }
+  fds->handles_pos = woff;
+  return woff;
+}
+
+
+/**
  * Check if sockets or pipes meet certain conditions, version for W32.
  *
  * @param rfds set of sockets or pipes to be checked for readability
@@ -1536,93 +1753,44 @@
                               struct GNUNET_NETWORK_FDSet *efds,
                               const struct GNUNET_TIME_Relative timeout)
 {
-  int nfds = 0;
-  int handles = 0;
-  int ex_handles = 0;
-  int read_handles = 0;
-  int write_handles = 0;
-
-  int i = 0;
-  int retcode = 0;
-  uint64_t mcs_total = 0;
-  DWORD ms_rounded = 0;
-
+  struct GNUNET_DISK_FileHandle *fh;
+  int nfds;
+  int handles;
+  unsigned int i;
+  int retcode;
+  uint64_t mcs_total;
+  DWORD ms_rounded;
   int nhandles = 0;
-
-  static HANDLE hEventPipeWrite = 0;
-  static HANDLE hEventReadReady = 0;
-
-  static struct _select_params sp;
-  static HANDLE select_thread = NULL;
-  static HANDLE select_finished_event = NULL;
-  static HANDLE select_standby_event = NULL;
-  static SOCKET select_wakeup_socket = -1;
-  static SOCKET select_send_socket = -1;
-  static struct timeval select_timeout;
-
-  int readPipes = 0;
-  int writePipePos = 0;
-
+  int read_pipes_off;
   HANDLE handle_array[FD_SETSIZE + 2];
-  int returncode = -1;
+  int returncode;
   int returnedpos = 0;
-
-  struct GNUNET_CONTAINER_SList *handles_read;
-  struct GNUNET_CONTAINER_SList *handles_write;
-  struct GNUNET_CONTAINER_SList *handles_except;
-
-  int selectret = 0;
-
+  int selectret;
   fd_set aread;
   fd_set awrite;
   fd_set aexcept;
 
-#if DEBUG_NETWORK
-  fd_set bread;
-  fd_set bwrite;
-  fd_set bexcept;
-#endif
-
-  /* TODO: Make this growable */
-  struct GNUNET_DISK_FileHandle *readArray[50];
-  struct timeval tv;
-
+  nfds = 0;
+  handles = 0;
   if (NULL != rfds)
   {
-    nfds = rfds->nsds;
-    handles += read_handles = GNUNET_CONTAINER_slist_count (rfds->handles);
-#if DEBUG_NETWORK
-    {
-      struct GNUNET_CONTAINER_SList_Iterator t;
-
-      for (t = GNUNET_CONTAINER_slist_begin (rfds->handles);
-           GNUNET_CONTAINER_slist_end (&t) != GNUNET_YES;
-           GNUNET_CONTAINER_slist_next (&t))
-      {
-        struct GNUNET_DISK_FileHandle *fh;
-
-        fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&t,
-                                                                           
NULL);
-        LOG (GNUNET_ERROR_TYPE_DEBUG, "FD 0x%x (0x%x) is SET in rfds\n", fh->h,
-             fh);
-      }
-    }
-#endif
+    nfds = GNUNET_MAX (nfds, rfds->nsds);
+    handles += rfds->handles_pos;
   }
   if (NULL != wfds)
   {
     nfds = GNUNET_MAX (nfds, wfds->nsds);
-    handles += write_handles = GNUNET_CONTAINER_slist_count (wfds->handles);
+    handles += wfds->handles_pos;
   }
   if (NULL != efds)
   {
     nfds = GNUNET_MAX (nfds, efds->nsds);
-    handles += ex_handles = GNUNET_CONTAINER_slist_count (efds->handles);
+    handles += efds->handles_pos;
   }
 
-  if ((nfds == 0) &&
-      (timeout.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
-      && (handles == 0) )
+  if ((0 == nfds) &&
+      (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == timeout.rel_value_us) &&
+      (0 == handles) )
   {
     GNUNET_break (0);
     LOG (GNUNET_ERROR_TYPE_ERROR,
@@ -1644,97 +1812,28 @@
       ms_rounded = 1;
   }
   /* select() may be used as a portable way to sleep */
-  if (!(rfds || wfds || efds))
+  if (! (rfds || wfds || efds))
   {
     Sleep (ms_rounded);
     return 0;
   }
 
   if (NULL == select_thread)
-  {
-    SOCKET select_listening_socket = -1;
-    struct sockaddr_in s_in;
-    int alen;
-    int res;
-    unsigned long p;
+    initialize_select_thread ();
 
-    select_standby_event = CreateEvent (NULL, TRUE, FALSE, NULL);
-    select_finished_event = CreateEvent (NULL, TRUE, FALSE, NULL);
-
-    select_wakeup_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
-
-    select_listening_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
-
-    p = 1;
-    res = ioctlsocket (select_wakeup_socket, FIONBIO, &p);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Select thread initialization: ioctlsocket() 
returns %d\n", res);
-
-    alen = sizeof (s_in);
-    s_in.sin_family = AF_INET;
-    s_in.sin_port = 0;
-    s_in.sin_addr.S_un.S_un_b.s_b1 = 127;
-    s_in.sin_addr.S_un.S_un_b.s_b2 = 0;
-    s_in.sin_addr.S_un.S_un_b.s_b3 = 0;
-    s_in.sin_addr.S_un.S_un_b.s_b4 = 1;
-    res = bind (select_listening_socket, (const struct sockaddr *) &s_in, 
sizeof (s_in));
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Select thread initialization: bind() 
returns %d\n", res);
-
-    res = getsockname (select_listening_socket, (struct sockaddr *) &s_in, 
&alen);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Select thread initialization: getsockname() 
returns %d\n", res);
-
-    res = listen (select_listening_socket, SOMAXCONN);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Select thread initialization: listen() 
returns %d\n", res);
-
-    res = connect (select_wakeup_socket, (const struct sockaddr *) &s_in, 
sizeof (s_in));
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Select thread initialization: connect() 
returns %d\n", res);
-
-    select_send_socket = accept (select_listening_socket, (struct sockaddr *) 
&s_in, &alen);
-
-    closesocket (select_listening_socket);
-
-    sp.wakeup = select_finished_event;
-    sp.standby = select_standby_event;
-    sp.wakeup_socket = select_wakeup_socket;
-
-    select_thread = CreateThread (NULL, 0, _selector, &sp, 0, NULL);
-  }
-
-
-  handles_read = GNUNET_CONTAINER_slist_create ();
-  handles_write = GNUNET_CONTAINER_slist_create ();
-  handles_except = GNUNET_CONTAINER_slist_create ();
   FD_ZERO (&aread);
   FD_ZERO (&awrite);
   FD_ZERO (&aexcept);
-#if DEBUG_NETWORK
-  FD_ZERO (&bread);
-  FD_ZERO (&bwrite);
-  FD_ZERO (&bexcept);
-#endif
   if (rfds)
-  {
     FD_COPY (&rfds->sds, &aread);
-#if DEBUG_NETWORK
-    FD_COPY (&rfds->sds, &bread);
-#endif
-  }
   if (wfds)
-  {
     FD_COPY (&wfds->sds, &awrite);
-#if DEBUG_NETWORK
-    FD_COPY (&wfds->sds, &bwrite);
-#endif
-  }
   if (efds)
-  {
     FD_COPY (&efds->sds, &aexcept);
-#if DEBUG_NETWORK
-    FD_COPY (&efds->sds, &bexcept);
-#endif
-  }
 
-  /* Start by doing a fast check on sockets and pipes (without waiting). It is 
cheap, and is sufficient most of the time.
-     By profiling we detected that to be true in 90% of the cases.
+  /* Start by doing a fast check on sockets and pipes (without
+     waiting). It is cheap, and is sufficient most of the time.  By
+     profiling we detected that to be true in 90% of the cases.
   */
 
   /* Do the select now */
@@ -1743,141 +1842,81 @@
 
   /* Copy all the writes to the except, so we can detect connect() errors */
   for (i = 0; i < awrite.fd_count; i++)
-    FD_SET (awrite.fd_array[i], &aexcept);
-  if (aread.fd_count > 0 || awrite.fd_count > 0 || aexcept.fd_count > 0)
-    selectret = select (1, (rfds != NULL) ? &aread : NULL,
-        (wfds != NULL) ? &awrite : NULL, &aexcept, &select_timeout);
+    FD_SET (awrite.fd_array[i],
+            &aexcept);
+  if ( (aread.fd_count > 0) ||
+       (awrite.fd_count > 0) ||
+       (aexcept.fd_count > 0) )
+    selectret = select (1,
+                        (NULL != rfds) ? &aread : NULL,
+                        (NULL != wfds) ? &awrite : NULL,
+                        &aexcept,
+                        &select_timeout);
   else
     selectret = 0;
-  if (selectret == -1)
+  if (-1 == selectret)
   {
     /* Throw an error early on, while we still have the context. */
-    LOG (GNUNET_ERROR_TYPE_ERROR, "W32 select(%d, %d, %d) failed: %lu\n",
-        rfds ? aread.fd_count : 0, wfds ? awrite.fd_count : 0, 
aexcept.fd_count, GetLastError ());
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         "W32 select(%d, %d, %d) failed: %lu\n",
+         rfds ? aread.fd_count : 0,
+         wfds ? awrite.fd_count : 0,
+         aexcept.fd_count,
+         GetLastError ());
     GNUNET_abort ();
   }
 
-  /* Check aexcept, add its contents to awrite
-     This is technically wrong (aexcept might have its own descriptors), we 
should
-     have checked that descriptors were in awrite originally before re-adding 
them from
-     aexcept. Luckily, GNUnet never uses aexcept for anything, so this does 
not become a problem (yet). */
-  for (i = 0; i < aexcept.fd_count; i++)
-    FD_SET (aexcept.fd_array[i], &awrite);
+  /* Check aexcept, if something is in there and we copied that
+     FD before to detect connect() errors, add it back to the
+     write set to report errors. */
+  if (NULL != wfds)
+    for (i = 0; i < aexcept.fd_count; i++)
+      if (FD_ISSET (aexcept.fd_array[i],
+                    &wfds->sds))
+        FD_SET (aexcept.fd_array[i],
+                &awrite);
 
-  /* If our select returned something or is a 0-timed request, then also check 
the pipes and get out of here! */
+
+  /* If our select returned something or is a 0-timed request, then
+     also check the pipes and get out of here! */
   /* Sadly, it means code duplication :( */
-  if ((selectret > 0) || (mcs_total == 0))
+  if ( (selectret > 0) || (0 == mcs_total) )
   {
+    retcode = 0;
+
     /* Read Pipes */
-    if (rfds && read_handles)
-    {
-      struct GNUNET_CONTAINER_SList_Iterator i;
-      int c;
+    if (rfds && (rfds->handles_pos > 0))
+      retcode += check_handles_status (rfds, GNUNET_NO);
 
-      for (c = 0, i = GNUNET_CONTAINER_slist_begin (rfds->handles);
-          GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES;
-          GNUNET_CONTAINER_slist_next (&i), c++)
-      {
-        struct GNUNET_DISK_FileHandle *fh;
+    /* wfds handles remain untouched, on W32
+       we pretend our pipes are "always" write-ready */
 
-        fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get 
(&i,NULL);
-        if (fh->type == GNUNET_DISK_HANLDE_TYPE_PIPE)
-        {
-          DWORD error;
-          BOOL bret;
+    /* except pipes */
+    if (efds && (efds->handles_pos > 0))
+      retcode += check_handles_status (efds, GNUNET_YES);
 
-          SetLastError (0);
-          DWORD waitstatus = 0;
-          bret = PeekNamedPipe (fh->h, NULL, 0, NULL, &waitstatus, NULL);
-          error = GetLastError ();
-          LOG (GNUNET_ERROR_TYPE_DEBUG, "Peek at read pipe %d (0x%x) returned 
%d (%d bytes available) GLE %u\n",
-              c, fh->h, bret, waitstatus, error);
-          if (bret == 0)
-          {
-            /* TODO: either add more errors to this condition, or eliminate it
-             * entirely (failed to peek -> pipe is in serious trouble, should
-             * be selected as readable).
-             */
-            if (error != ERROR_BROKEN_PIPE && error != ERROR_INVALID_HANDLE)
-              continue;
-          }
-          else if (waitstatus <= 0)
-            continue;
-          GNUNET_CONTAINER_slist_add (handles_read, 
GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
-              fh, sizeof (struct GNUNET_DISK_FileHandle));
-          retcode++;
-          LOG (GNUNET_ERROR_TYPE_DEBUG, "Added read Pipe 0x%x (0x%x)\n",
-              fh, fh->h);
-        }
-        else
-        {
-          GNUNET_CONTAINER_slist_add (handles_read, 
GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
-              fh, sizeof (struct GNUNET_DISK_FileHandle));
-          retcode++;
-        }
-      }
-    }
-    if (wfds && write_handles)
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-          "Adding the write ready event to the array as %d\n", nhandles);
-      GNUNET_CONTAINER_slist_append (handles_write, wfds->handles);
-      retcode += write_handles;
-    }
-    if (efds && ex_handles)
-    {
-      struct GNUNET_CONTAINER_SList_Iterator i;
-
-      for (i = GNUNET_CONTAINER_slist_begin (efds->handles);
-          GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES;
-          GNUNET_CONTAINER_slist_next (&i))
-      {
-        struct GNUNET_DISK_FileHandle *fh;
-        DWORD dwBytes;
-
-        fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&i, 
NULL);
-        if (fh->type == GNUNET_DISK_HANLDE_TYPE_PIPE)
-        {
-          if (PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL))
-            continue;
-          GNUNET_CONTAINER_slist_add (handles_except, 
GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
-              fh, sizeof (struct GNUNET_DISK_FileHandle));
-          retcode++;
-        }
-      }
-    }
-
-    /* Add our select() result.*/
-    if (selectret >= 0)
-      retcode += selectret;
-
     if (rfds)
     {
       GNUNET_NETWORK_fdset_zero (rfds);
       if (selectret != -1)
         GNUNET_NETWORK_fdset_copy_native (rfds, &aread, selectret);
-      GNUNET_CONTAINER_slist_append (rfds->handles, handles_read);
     }
     if (wfds)
     {
       GNUNET_NETWORK_fdset_zero (wfds);
       if (selectret != -1)
         GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, selectret);
-      GNUNET_CONTAINER_slist_append (wfds->handles, handles_write);
     }
     if (efds)
     {
       GNUNET_NETWORK_fdset_zero (efds);
       if (selectret != -1)
         GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, selectret);
-      GNUNET_CONTAINER_slist_append (efds->handles, handles_except);
     }
-    GNUNET_CONTAINER_slist_destroy (handles_read);
-    GNUNET_CONTAINER_slist_destroy (handles_write);
-    GNUNET_CONTAINER_slist_destroy (handles_except);
-
-    if (selectret == -1)
+    if (-1 == selectret)
       return -1;
+    /* Add our select() FDs to the total return value */
+    retcode += selectret;
     return retcode;
   }
 
@@ -1885,134 +1924,69 @@
      on both sockets and pipes simultaneously */
 
   /* Events for pipes */
-  if (!hEventReadReady)
+  if (! hEventReadReady)
     hEventReadReady = CreateEvent (NULL, TRUE, TRUE, NULL);
-  if (!hEventPipeWrite)
+  if (! hEventPipeWrite)
     hEventPipeWrite = CreateEvent (NULL, TRUE, TRUE, NULL);
-  readPipes = 0;
-  writePipePos = -1;
-
   retcode = 0;
 
   FD_ZERO (&aread);
   FD_ZERO (&awrite);
   FD_ZERO (&aexcept);
-#if DEBUG_NETWORK
-  FD_ZERO (&bread);
-  FD_ZERO (&bwrite);
-  FD_ZERO (&bexcept);
-#endif
   if (rfds)
-  {
     FD_COPY (&rfds->sds, &aread);
-#if DEBUG_NETWORK
-    FD_COPY (&rfds->sds, &bread);
-#endif
-  }
   if (wfds)
-  {
     FD_COPY (&wfds->sds, &awrite);
-#if DEBUG_NETWORK
-    FD_COPY (&wfds->sds, &bwrite);
-#endif
-  }
   if (efds)
-  {
     FD_COPY (&efds->sds, &aexcept);
-#if DEBUG_NETWORK
-    FD_COPY (&efds->sds, &bexcept);
-#endif
-  }
   /* We will first Add the PIPES to the events */
-  /* Read Pipes */
-  if (rfds && read_handles)
+  /* Track how far in `handle_array` the read pipes go,
+     so we may by-pass them quickly if none of them
+     are selected. */
+  read_pipes_off = 0;
+  if (rfds && (rfds->handles_pos > 0))
   {
-    struct GNUNET_CONTAINER_SList_Iterator i;
-
-    for (i = GNUNET_CONTAINER_slist_begin (rfds->handles);
-         GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES;
-         GNUNET_CONTAINER_slist_next (&i))
+    for (i = 0; i <rfds->handles_pos; i++)
     {
-      struct GNUNET_DISK_FileHandle *fh;
+      fh = rfds->handles[i];
+      if (fh->type != GNUNET_DISK_HANLDE_TYPE_PIPE)
+        continue;
+      /* Read zero bytes to check the status of the pipe */
+      if (! ReadFile (fh->h, NULL, 0, NULL, fh->oOverlapRead))
+      {
+        DWORD error_code = GetLastError ();
 
-      fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&i,
-                                                                         NULL);
-      if (fh->type == GNUNET_DISK_HANLDE_TYPE_PIPE)
-      {
-        /* Read zero bytes to check the status of the pipe */
-        LOG (GNUNET_ERROR_TYPE_DEBUG, "Reading 0 bytes from the pipe 0x%x\n",
-             fh->h);
-        if (!ReadFile (fh->h, NULL, 0, NULL, fh->oOverlapRead))
+        if (error_code == ERROR_IO_PENDING)
         {
-          DWORD error_code = GetLastError ();
-
-          if (error_code == ERROR_IO_PENDING)
-          {
-            LOG (GNUNET_ERROR_TYPE_DEBUG,
-                 "Adding the pipe's 0x%x overlapped event to the array as 
%d\n",
-                 fh->h, nhandles);
-            handle_array[nhandles++] = fh->oOverlapRead->hEvent;
-            readArray[readPipes++] = fh;
-          }
-          else
-          {
-            LOG (GNUNET_ERROR_TYPE_DEBUG,
-                 "Read failed, adding the read ready event to the array as 
%d\n", nhandles);
-            handle_array[nhandles++] = hEventReadReady;
-            readArray[readPipes++] = fh;
-          }
+          /* add as unready */
+          handle_array[nhandles++] = fh->oOverlapRead->hEvent;
+          read_pipes_off++;
         }
         else
         {
-          LOG (GNUNET_ERROR_TYPE_DEBUG,
-               "Adding the read ready event to the array as %d\n", nhandles);
+          /* add as ready */
           handle_array[nhandles++] = hEventReadReady;
-          readArray[readPipes++] = fh;
+          read_pipes_off++;
         }
       }
       else
       {
-        GNUNET_CONTAINER_slist_add (handles_read,
-                                    
GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
-                                    fh, sizeof (struct 
GNUNET_DISK_FileHandle));
+        /* error also counts as ready */
+        handle_array[nhandles++] = hEventReadReady;
+        read_pipes_off++;
       }
     }
   }
-  if (wfds && write_handles)
+
+  if (wfds && (wfds->handles_pos > 0))
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Adding the write ready event to the array as %d\n", nhandles);
+         "Adding the write ready event to the array as %d\n",
+         nhandles);
     handle_array[nhandles++] = hEventPipeWrite;
-    writePipePos = nhandles;
   }
-  if (efds && ex_handles)
-  {
-    struct GNUNET_CONTAINER_SList_Iterator i;
 
-    for (i = GNUNET_CONTAINER_slist_begin (efds->handles);
-         GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES;
-         GNUNET_CONTAINER_slist_next (&i))
-    {
-      struct GNUNET_DISK_FileHandle *fh;
-      DWORD dwBytes;
-
-      fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&i,
-                                                                         NULL);
-      if (fh->type == GNUNET_DISK_HANLDE_TYPE_PIPE)
-      {
-        if (!PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL))
-        {
-          GNUNET_CONTAINER_slist_add (handles_except,
-                                      
GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
-                                      fh,
-                                      sizeof (struct GNUNET_DISK_FileHandle));
-        }
-      }
-    }
-  }
-
   sp.status = 0;
-
   if (nfds > 0)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -2122,147 +2096,48 @@
        "return pos is: %d\n",
        returnedpos);
 
-  if (nhandles && (returnedpos < nhandles))
+  if (rfds)
   {
-    DWORD waitstatus;
-
-    if (sp.status > 0)
-      retcode += sp.status;
-
-    if ((writePipePos != -1) && (returnedpos < writePipePos))
+    /* We queued a zero-long read on each pipe to check
+     * its state, now we must cancel these read operations.
+     * This must be done while rfds->handles_pos is still
+     * intact and matches the number of read handles that we
+     * got from the caller.
+     */
+    for (i = 0; i < rfds->handles_pos; i++)
     {
-      GNUNET_CONTAINER_slist_append (handles_write, wfds->handles);
-      retcode += write_handles;
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Added write pipe\n");
+      fh = rfds->handles[i];
+      if (GNUNET_DISK_HANLDE_TYPE_PIPE == fh->type)
+        CancelIo (fh->h);
     }
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "ReadPipes is: %d\n",
-         readPipes);
-    /* We have some pipes ready for read. */
-    if (returnedpos < readPipes)
-    {
-      for (i = 0; i < readPipes; i++)
-      {
-        DWORD error;
-        BOOL bret;
 
-        SetLastError (0);
-        waitstatus = 0;
-        bret =
-            PeekNamedPipe (readArray[i]->h, NULL, 0, NULL, &waitstatus, NULL);
-        error = GetLastError ();
-        LOG (GNUNET_ERROR_TYPE_DEBUG,
-             "Peek at read pipe %d (0x%x) returned %d (%d bytes available) GLE 
%u\n",
-             i, readArray[i]->h, bret, waitstatus, error);
-        if (bret == 0)
-        {
-          /* TODO: either add more errors to this condition, or eliminate it
-           * entirely (failed to peek -> pipe is in serious trouble, should
-           * be selected as readable).
-           */
-          if (error != ERROR_BROKEN_PIPE && error != ERROR_INVALID_HANDLE)
-            continue;
-        }
-        else if (waitstatus <= 0)
-          continue;
-        GNUNET_CONTAINER_slist_add (handles_read,
-                                    
GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
-                                    readArray[i],
-                                    sizeof (struct GNUNET_DISK_FileHandle));
-        retcode++;
-        LOG (GNUNET_ERROR_TYPE_DEBUG, "Added read Pipe 0x%x (0x%x)\n",
-             readArray[i], readArray[i]->h);
-      }
-    }
-  }
-  if (! nhandles || (returnedpos >= nhandles))
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Returning from _select() with nothing!\n");
-  if (rfds)
-  {
-    struct GNUNET_CONTAINER_SList_Iterator t;
+    /* We may have some pipes ready for reading. */
+    if (returnedpos < read_pipes_off)
+      retcode += check_handles_status (rfds, GNUNET_NO);
+    else
+      rfds->handles_pos = 0;
 
-    for (t = GNUNET_CONTAINER_slist_begin (rfds->handles);
-         GNUNET_CONTAINER_slist_end (&t) != GNUNET_YES;
-         GNUNET_CONTAINER_slist_next (&t))
-    {
-      struct GNUNET_DISK_FileHandle *fh;
-
-      fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&t,
-                                                                         NULL);
-      if (fh->type == GNUNET_DISK_HANLDE_TYPE_PIPE)
-      {
-        CancelIo (fh->h);
-      }
-    }
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Zeroing rfds%s\n", (retcode != -1 && 
nhandles && (returnedpos < nhandles)) ? ", copying fdset" : "");
-    GNUNET_NETWORK_fdset_zero (rfds);
-    if (retcode != -1 && nhandles && (returnedpos < nhandles))
+    if (-1 != sp.status)
       GNUNET_NETWORK_fdset_copy_native (rfds, &aread, retcode);
-    GNUNET_CONTAINER_slist_append (rfds->handles, handles_read);
   }
   if (wfds)
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Zeroing wfds%s\n", (retcode != -1 && 
nhandles && (returnedpos < nhandles)) ? ", copying fdset" : "");
-    GNUNET_NETWORK_fdset_zero (wfds);
-    if (retcode != -1 && nhandles && (returnedpos < nhandles))
+    retcode += wfds->handles_pos;
+    /* wfds handles remain untouched */
+    if (-1 != sp.status)
       GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, retcode);
-    GNUNET_CONTAINER_slist_append (wfds->handles, handles_write);
   }
   if (efds)
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Zeroing efds%s\n", (retcode != -1 && 
nhandles && (returnedpos < nhandles)) ? ", copying fdset" : "");
-    GNUNET_NETWORK_fdset_zero (efds);
-    if (retcode != -1 && nhandles && (returnedpos < nhandles))
+    retcode += check_handles_status (rfds, GNUNET_YES);
+    if (-1 != sp.status)
       GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, retcode);
-    GNUNET_CONTAINER_slist_append (efds->handles, handles_except);
   }
-  GNUNET_CONTAINER_slist_destroy (handles_read);
-  GNUNET_CONTAINER_slist_destroy (handles_write);
-  GNUNET_CONTAINER_slist_destroy (handles_except);
-#if DEBUG_NETWORK
-  if (rfds)
-  {
-    struct GNUNET_CONTAINER_SList_Iterator t;
 
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "rfds:\n");
-    for (i = 0; i < rfds->sds.fd_count; i++)
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "%d\n", rfds->sds.fd_array[i]);
-    }
-    for (t = GNUNET_CONTAINER_slist_begin (rfds->handles);
-         GNUNET_CONTAINER_slist_end (&t) != GNUNET_YES;
-         GNUNET_CONTAINER_slist_next (&t))
-    {
-      struct GNUNET_DISK_FileHandle *fh;
+  if (sp.status > 0)
+    retcode += sp.status;
 
-      fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&t,
-                                                                         NULL);
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "%d\n", fh->h);
-    }
-  }
-  if (wfds)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "wfds:\n");
-    for (i = 0; i < wfds->sds.fd_count; i++)
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "%d\n", wfds->sds.fd_array[i]);
-    }
-  }
-  if (efds)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "efds:\n");
-    for (i = 0; i < efds->sds.fd_count; i++)
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "%d\n", efds->sds.fd_array[i]);
-    }
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Returning %d or 0\n", retcode);
-#endif
-  if (nhandles && (returnedpos < nhandles))
-    return retcode;
-  return 0;
+  return retcode;
 }
 
 /* MINGW */




reply via email to

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