LRN: enable more fine-grained control over blocking/non-blocking pipe operation
authorChristian Grothoff <christian@grothoff.org>
Sat, 14 Jan 2012 23:18:06 +0000 (23:18 +0000)
committerChristian Grothoff <christian@grothoff.org>
Sat, 14 Jan 2012 23:18:06 +0000 (23:18 +0000)
14 files changed:
src/arm/gnunet-service-arm.c
src/fs/fs_dirmetascan.c
src/include/gnunet_disk_lib.h
src/nat/nat.c
src/nat/nat_mini.c
src/testing/testing.c
src/transport/plugin_transport_wlan.c
src/util/disk.c
src/util/helper.c
src/util/os_priority.c
src/util/scheduler.c
src/util/test_common_logging_runtime_loglevels.c
src/util/test_os_start_process.c
src/util/test_scheduler.c

index 4c78e6fe760902f75e325db8acb35c413762999d..88fabef2fccc6782f81ded5da9ebb026c1add8fd 100644 (file)
@@ -1174,7 +1174,7 @@ main (int argc, char *const *argv)
   int ret;
   struct GNUNET_SIGNAL_Context *shc_chld;
 
-  sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO);
+  sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO);
   GNUNET_assert (sigpipe != NULL);
   shc_chld =
     GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
index 880710356d64c17f7711991f8cb0d7a9ec5f9666..ce76b03875cbabf99d2eefcb6c931020751a74ce 100644 (file)
@@ -1047,7 +1047,7 @@ GNUNET_FS_directory_scan_start (const char *filename,
   if (filename_expanded == NULL)\r
     return NULL;\r
 \r
-  progress_pipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO);\r
+  progress_pipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO);\r
   if (progress_pipe == NULL)\r
   {\r
     GNUNET_free (filename_expanded);\r
index be92a91c6e2554545a66dc3e86cdb5f8fb979d2f..46dd7c4c40ab24bfd503ae40fe1986f0b6bafa17 100644 (file)
@@ -395,7 +395,7 @@ GNUNET_DISK_file_handle_size (struct GNUNET_DISK_FileHandle *fh,
  * @return handle to the new pipe, NULL on error
  */
 struct GNUNET_DISK_PipeHandle *
-GNUNET_DISK_pipe (int blocking, int inherit_read, int inherit_write);
+GNUNET_DISK_pipe (int blocking_read, int blocking_write, int inherit_read, int inherit_write);
 
 
 /**
@@ -408,7 +408,7 @@ GNUNET_DISK_pipe (int blocking, int inherit_read, int inherit_write);
  * @return handle to the new pipe, NULL on error
  */
 struct GNUNET_DISK_PipeHandle *
-GNUNET_DISK_pipe_from_fd (int blocking, int fd[2]);
+GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2]);
 
 /**
  * Closes an interprocess channel
@@ -461,6 +461,19 @@ ssize_t
 GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle *h, void *result,
                        size_t len);
 
+/**
+ * Read the contents of a binary file into a buffer.
+ * Guarantees not to block (returns GNUNET_SYSERR and sets errno to EAGAIN
+ * when no data can be read).
+ *
+ * @param h handle to an open file
+ * @param result the buffer to write the result to
+ * @param len the maximum number of bytes to read
+ * @return the number of bytes read on success, GNUNET_SYSERR on failure
+ */
+ssize_t
+GNUNET_DISK_file_read_non_blocking (const struct GNUNET_DISK_FileHandle * h,
+    void *result, size_t len);
 
 /**
  * Read the contents of a binary file into a buffer.
@@ -487,6 +500,17 @@ GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle *h,
                         const void *buffer, size_t n);
 
 
+/**
+ * Write a buffer to a file, blocking, if necessary.
+ * @param h handle to open file
+ * @param buffer the data to write
+ * @param n number of bytes to write
+ * @return number of bytes written on success, GNUNET_SYSERR on error
+ */
+ssize_t
+GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle * h,
+    const void *buffer, size_t n);
+
 /**
  * Write a buffer to a file.  If the file is longer than
  * the given buffer size, it will be truncated.
index 9f8fec9a022fc004eb018fe7f2ec6d5d4c649038..02ff7547b6fcd0ceb1bda78d2f6bf15b11d3f616 100644 (file)
@@ -835,7 +835,7 @@ start_gnunet_nat_server (struct GNUNET_NAT_Handle *h)
       (h->internal_address != NULL) &&
       (NULL !=
        (h->server_stdout =
-        GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES))))
+        GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES))))
   {
 #if DEBUG_NAT
     LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting `%s' at `%s'\n",
index 5a83d7a4fea22e7dd4ce3b013d9d7aee494175b0..6c48f28fec775e7fbfa06e5723e357bc6b68cd3b 100644 (file)
@@ -169,7 +169,7 @@ GNUNET_NAT_mini_get_external_ipv4 (struct GNUNET_TIME_Relative timeout,
   eh = GNUNET_malloc (sizeof (struct GNUNET_NAT_ExternalHandle));
   eh->cb = cb;
   eh->cb_cls = cb_cls;
-  eh->opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES);
+  eh->opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES);
   if (NULL == eh->opipe)
   {
     GNUNET_free (eh);
index d7f6946b0f7087adfcef0be584d0f3813d3b40bb..a729c5063843263b1ce17704bd8b40031f32299c 100644 (file)
@@ -239,7 +239,7 @@ start_fsm (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     /* Start create hostkey process if we don't already know the peer identity! */
     if (GNUNET_NO == d->have_hostkey)
     {
-      d->pipe_stdout = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_YES);
+      d->pipe_stdout = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_YES);
       if (d->pipe_stdout == NULL)
       {
         cb = d->cb;
index d121ec9be1491e3b574c2c823acb638a42708082..5ac44c2f2c6c059b792c39aad775c230fe37cf97 100644 (file)
@@ -1441,11 +1441,11 @@ wlan_transport_start_wlan_helper (struct Plugin *plugin)
     return GNUNET_YES;
   }
 
-  plugin->server_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES);
+  plugin->server_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES);
   if (plugin->server_stdout == NULL)
     return GNUNET_SYSERR;
 
-  plugin->server_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO);
+  plugin->server_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO);
   if (plugin->server_stdin == NULL)
     return GNUNET_SYSERR;
 
index eb707fd62fdf8e08e5bd2d0a111a6231c477ab2a..a5190d587c773f031e2bf21852c55f6076108f8d 100644 (file)
@@ -746,6 +746,74 @@ GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle * h, void *result,
 #endif
 }
 
+/**
+ * Read the contents of a binary file into a buffer.
+ * Guarantees not to block (returns GNUNET_SYSERR and sets errno to EAGAIN
+ * when no data can be read).
+ *
+ * @param h handle to an open file
+ * @param result the buffer to write the result to
+ * @param len the maximum number of bytes to read
+ * @return the number of bytes read on success, GNUNET_SYSERR on failure
+ */
+ssize_t
+GNUNET_DISK_file_read_non_blocking (const struct GNUNET_DISK_FileHandle * h,
+    void *result, size_t len)
+{
+  if (h == NULL)
+  {
+    errno = EINVAL;
+    return GNUNET_SYSERR;
+  }
+
+#ifdef MINGW
+  DWORD bytesRead;
+
+  if (h->type != GNUNET_PIPE)
+  {
+    if (!ReadFile (h->h, result, len, &bytesRead, NULL))
+    {
+      SetErrnoFromWinError (GetLastError ());
+      return GNUNET_SYSERR;
+    }
+  }
+  else
+  {
+#if DEBUG_PIPE
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "It is a pipe, trying to read\n");
+#endif
+    if (!ReadFile (h->h, result, len, &bytesRead, h->oOverlapRead))
+    {
+      if (GetLastError () != ERROR_IO_PENDING)
+      {
+#if DEBUG_PIPE
+        LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ());
+#endif
+        SetErrnoFromWinError (GetLastError ());
+        return GNUNET_SYSERR;
+      }
+      else
+      {
+#if DEBUG_PIPE
+        LOG (GNUNET_ERROR_TYPE_DEBUG,
+            "ReadFile() queued a read, cancelling\n");
+#endif
+        CancelIo (h->h);
+        errno = EAGAIN;
+        return GNUNET_SYSERR;
+      }
+    }
+#if DEBUG_PIPE
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes\n", bytesRead);
+#endif
+  }
+  return bytesRead;
+#else
+  /* FIXME: set to non-blocking (fcntl?), read, then set back? */
+  return read (h->fd, result, len);
+#endif
+}
+
 
 /**
  * Read the contents of a binary file into a buffer.
@@ -870,6 +938,64 @@ GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle * h,
 #endif
 }
 
+/**
+ * Write a buffer to a file, blocking, if necessary.
+ * @param h handle to open file
+ * @param buffer the data to write
+ * @param n number of bytes to write
+ * @return number of bytes written on success, GNUNET_SYSERR on error
+ */
+ssize_t
+GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle * h,
+    const void *buffer, size_t n)
+{
+  if (h == NULL)
+  {
+    errno = EINVAL;
+    return GNUNET_SYSERR;
+  }
+
+#ifdef MINGW
+  DWORD bytesWritten;
+  /* We do a non-overlapped write, which is as blocking as it gets */
+#if DEBUG_PIPE
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Writing %u bytes\n", n);
+#endif
+  if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
+  {
+    SetErrnoFromWinError (GetLastError ());
+#if DEBUG_PIPE
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
+        GetLastError ());
+#endif
+    return GNUNET_SYSERR;
+  }
+  if (bytesWritten == 0 && n > 0)
+  {
+#if DEBUG_PIPE
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for pipe to clean\n");
+#endif
+    WaitForSingleObject (h->h, INFINITE);
+    if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
+    {
+      SetErrnoFromWinError (GetLastError ());
+#if DEBUG_PIPE
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
+          GetLastError ());
+#endif
+      return GNUNET_SYSERR;
+    }
+  }
+#if DEBUG_PIPE
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytesWritten);
+#endif
+  return bytesWritten;
+#else
+  /* FIXME: switch to blocking mode (fcntl?), write, then switch back? */
+  return write (h->fd, buffer, n);
+#endif
+}
+
 /**
  * Write a buffer to a file.  If the file is longer than the
  * number of bytes that will be written, it will be truncated.
@@ -1971,7 +2097,7 @@ create_selectable_pipe (PHANDLE read_pipe_ptr, PHANDLE write_pipe_ptr,
  * @return handle to the new pipe, NULL on error
  */
 struct GNUNET_DISK_PipeHandle *
-GNUNET_DISK_pipe (int blocking, int inherit_read, int inherit_write)
+GNUNET_DISK_pipe (int blocking_read, int blocking_write, int inherit_read, int inherit_write)
 {
   struct GNUNET_DISK_PipeHandle *p;
   struct GNUNET_DISK_FileHandle *fds;
@@ -2000,7 +2126,7 @@ GNUNET_DISK_pipe (int blocking, int inherit_read, int inherit_write)
   p->fd[1]->fd = fd[1];
   ret = 0;
   flags = fcntl (fd[0], F_GETFL);
-  if (!blocking)
+  if (!blocking_read)
     flags |= O_NONBLOCK;
   if (0 > fcntl (fd[0], F_SETFL, flags))
     ret = -1;
@@ -2010,7 +2136,7 @@ GNUNET_DISK_pipe (int blocking, int inherit_read, int inherit_write)
     ret = -1;
 
   flags = fcntl (fd[1], F_GETFL);
-  if (!blocking)
+  if (!blocking_write)
     flags |= O_NONBLOCK;
   if (0 > fcntl (fd[1], F_SETFL, flags))
     ret = -1;
@@ -2034,7 +2160,8 @@ GNUNET_DISK_pipe (int blocking, int inherit_read, int inherit_write)
 
   ret =
       create_selectable_pipe (&p->fd[0]->h, &p->fd[1]->h, NULL, 0,
-                              FILE_FLAG_OVERLAPPED, FILE_FLAG_OVERLAPPED);
+                              blocking_read ? 0 : FILE_FLAG_OVERLAPPED,
+                              blocking_write ? 0 : FILE_FLAG_OVERLAPPED);
   if (!ret)
   {
     GNUNET_free (p);
@@ -2066,15 +2193,7 @@ GNUNET_DISK_pipe (int blocking, int inherit_read, int inherit_write)
   }
   CloseHandle (p->fd[1]->h);
   p->fd[1]->h = tmp_handle;
-  if (!blocking)
-  {
-    DWORD mode;
 
-    mode = PIPE_NOWAIT;
-    SetNamedPipeHandleState (p->fd[0]->h, &mode, NULL, NULL);
-    SetNamedPipeHandleState (p->fd[1]->h, &mode, NULL, NULL);
-    /* this always fails on Windows 95, so we don't care about error handling */
-  }
   p->fd[0]->type = GNUNET_PIPE;
   p->fd[1]->type = GNUNET_PIPE;
 
@@ -2103,7 +2222,7 @@ GNUNET_DISK_pipe (int blocking, int inherit_read, int inherit_write)
  * @return handle to the new pipe, NULL on error
  */
 struct GNUNET_DISK_PipeHandle *
-GNUNET_DISK_pipe_from_fd (int blocking, int fd[2])
+GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2])
 {
   struct GNUNET_DISK_PipeHandle *p;
   struct GNUNET_DISK_FileHandle *fds;
@@ -2124,7 +2243,7 @@ GNUNET_DISK_pipe_from_fd (int blocking, int fd[2])
   if (fd[0] >= 0)
   {
     flags = fcntl (fd[0], F_GETFL);
-    if (!blocking)
+    if (!blocking_read)
       flags |= O_NONBLOCK;
     if (0 > fcntl (fd[0], F_SETFL, flags))
       ret = -1;
@@ -2137,7 +2256,7 @@ GNUNET_DISK_pipe_from_fd (int blocking, int fd[2])
   if (fd[1] >= 0)
   {
     flags = fcntl (fd[1], F_GETFL);
-    if (!blocking)
+    if (!blocking_write)
       flags |= O_NONBLOCK;
     if (0 > fcntl (fd[1], F_SETFL, flags))
       ret = -1;
@@ -2170,18 +2289,6 @@ GNUNET_DISK_pipe_from_fd (int blocking, int fd[2])
   else
     p->fd[1]->h = INVALID_HANDLE_VALUE;
 
-  if (!blocking)
-  {
-    DWORD mode;
-
-    mode = PIPE_NOWAIT;
-    if (p->fd[0]->h != INVALID_HANDLE_VALUE)
-      SetNamedPipeHandleState (p->fd[0]->h, &mode, NULL, NULL);
-    if (p->fd[1]->h != INVALID_HANDLE_VALUE)
-      SetNamedPipeHandleState (p->fd[1]->h, &mode, NULL, NULL);
-    /* this always fails on Windows 95, so we don't care about error handling */
-  }
-
   if (p->fd[0]->h != INVALID_HANDLE_VALUE)
   {
     p->fd[0]->type = GNUNET_PIPE;
index d4d26ba5138b70cb4b649216c503c22afd376c28..d0aab3ccf1cea2e1aac53be961be6181be48be8e 100644 (file)
@@ -286,8 +286,8 @@ helper_read (void *cls,
 static void
 start_helper (struct GNUNET_HELPER_Handle *h)
 {
-  h->helper_in = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO);
-  h->helper_out = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES);
+  h->helper_in = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO);
+  h->helper_out = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES);
   if ( (h->helper_in == NULL) || (h->helper_out == NULL))
   {
     /* out of file descriptors? try again later... */
index 13f002f5d70a7af487c22eb31d06d8d78b2b16fc..b344cd86235eab02db3e0a8ad34e7f95fa35fce8 100644 (file)
@@ -1135,7 +1135,7 @@ GNUNET_OS_start_process_v (const SOCKTYPE *lsocks,
   }
   if (lsocks != NULL && lsocks[0] != INVALID_SOCKET)
   {
-    lsocks_pipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO);
+    lsocks_pipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO);
 
     if (lsocks_pipe == NULL)
     {
@@ -1582,7 +1582,7 @@ GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls,
   struct GNUNET_DISK_PipeHandle *opipe;
   va_list ap;
 
-  opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES);
+  opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES);
   if (NULL == opipe)
     return NULL;
   va_start (ap, binary);
index 5f91ffbbc8f6daf184392809c0e865a0105d1885..4128969466e72f83c40db5978e234a6305f67717 100644 (file)
@@ -803,7 +803,7 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
   rs = GNUNET_NETWORK_fdset_create ();
   ws = GNUNET_NETWORK_fdset_create ();
   GNUNET_assert (shutdown_pipe_handle == NULL);
-  shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO);
+  shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO);
   GNUNET_assert (shutdown_pipe_handle != NULL);
   pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle,
                                 GNUNET_DISK_PIPE_END_READ);
index 51123d9b3716241d9de3053d949dd43c043b8bc3..092f0604118851b6b8fa2b2f21f5f3c2ce19fb5f 100644 (file)
@@ -268,7 +268,7 @@ runone ()
 {
   const struct GNUNET_DISK_FileHandle *stdout_read_handle;
 
-  pipe_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES);
+  pipe_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES);
 
   if (pipe_stdout == NULL)
   {
index 78538404a6b6179b0058590edd8d26d13b680583..f66e741d9f7be9b3f473597e3a62707c961478e2 100644 (file)
@@ -114,8 +114,8 @@ task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 
   GNUNET_asprintf (&fn, "cat");
 
-  hello_pipe_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO);
-  hello_pipe_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES);
+  hello_pipe_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO);
+  hello_pipe_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES);
 
   if ((hello_pipe_stdout == NULL) || (hello_pipe_stdin == NULL))
   {
index 788ba13fa6a79dbffcd8137bb2feccc7493fe427..8072feaf177e0016128bb9d4abd1bf3596d781b3 100644 (file)
@@ -119,7 +119,7 @@ task5 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 
   GNUNET_assert (5 == *ok);
   (*ok) = 6;
-  p = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO);
+  p = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO);
   GNUNET_assert (NULL != p);
   fds[0] = GNUNET_DISK_pipe_handle (p, GNUNET_DISK_PIPE_END_READ);
   fds[1] = GNUNET_DISK_pipe_handle (p, GNUNET_DISK_PIPE_END_WRITE);